/*
    File:       DispatchLite.c
    Package:    Apple CarPlay Communication Plug-in.
    Abstract:   n/a
    Version:    420.2

    Disclaimer: IMPORTANT: This Apple software is supplied to you, by Apple Inc. ("Apple"), in your
    capacity as a current, and in good standing, Licensee in the MFi Licensing Program. Use of this
    Apple software is governed by and subject to the terms and conditions of your MFi License,
    including, but not limited to, the restrictions specified in the provision entitled ”Public
    Software”, and is further subject to your agreement to the following additional terms, and your
    agreement that the use, installation, modification or redistribution of this Apple software
    constitutes acceptance of these additional terms. If you do not agree with these additional terms,
    please do not use, install, modify or redistribute this Apple software.

    Subject to all of these terms and in consideration of your agreement to abide by them, Apple grants
    you, for as long as you are a current and in good-standing MFi Licensee, a personal, non-exclusive
    license, under Apple's copyrights in this original Apple software (the "Apple Software"), to use,
    reproduce, and modify the Apple Software in source form, and to use, reproduce, modify, and
    redistribute the Apple Software, with or without modifications, in binary form. While you may not
    redistribute the Apple Software in source form, should you redistribute the Apple Software in binary
    form, you must retain this notice and the following text and disclaimers in all such redistributions
    of the Apple Software. Neither the name, trademarks, service marks, or logos of Apple Inc. may be
    used to endorse or promote products derived from the Apple Software without specific prior written
    permission from Apple. Except as expressly stated in this notice, no other rights or licenses,
    express or implied, are granted by Apple herein, including but not limited to any patent rights that
    may be infringed by your derivative works or by other works in which the Apple Software may be
    incorporated.

    Unless you explicitly state otherwise, if you provide any ideas, suggestions, recommendations, bug
    fixes or enhancements to Apple in connection with this software (“Feedback”), you hereby grant to
    Apple a non-exclusive, fully paid-up, perpetual, irrevocable, worldwide license to make, use,
    reproduce, incorporate, modify, display, perform, sell, make or have made derivative works of,
    distribute (directly or indirectly) and sublicense, such Feedback in connection with Apple products
    and services. Providing this Feedback is voluntary, but if you do provide Feedback to Apple, you
    acknowledge and agree that Apple may exercise the license granted above without the payment of
    royalties or further consideration to Participant.

    The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, EXPRESS OR
    IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY
    AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR
    IN COMBINATION WITH YOUR PRODUCTS.

    IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
    PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION
    AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
    (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE
    POSSIBILITY OF SUCH DAMAGE.

    Copyright (C) 2008-2021 Apple Inc. All Rights Reserved. Not to be used or disclosed without permission from Apple.
*/

#include "DispatchLite.h"   // Include early for DISPATCH_LITE_*, etc. definitions.

#include "CommonServices.h" // Include early for TARGET_*, etc. definitions.
#include "DebugServices.h"  // Include early for DEBUG_*, etc. definitions.

#if( DISPATCH_LITE_ENABLED )

#include <errno.h>
#include <limits.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#if( DISPATCH_LITE_USE_KQUEUE )
#include <sys/event.h>
#endif

#if( TARGET_OS_POSIX )
#include <fcntl.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/time.h>
#endif

#include "AtomicUtils.h"
#include "StringUtils.h"
#include "ThreadUtils.h"
#include "TickUtils.h"

#if( DISPATCH_LITE_CF_ENABLED )
#include CF_HEADER
#endif

#if 0
#pragma mark == Constants and Types ==
#endif

//===========================================================================================================================
//  Constants and Types
//===========================================================================================================================

#if( !defined( TARGET_NO_PTHREAD_BROADCAST ) )
#define TARGET_NO_PTHREAD_BROADCAST             0
#endif

#if( TARGET_OS_WINDOWS )
#define kLibDispatchWindowEvent_Socket          ( WM_USER + 0x100 )
#define kLibDispatchWindowEvent_WorkPending     ( WM_USER + 0x101 )
#endif

// dispatch_base

struct dispatch_base_s {
    uint32_t                magic;
    int32_t                 refCount;
    void*                   context;
    dispatch_function_t     doFree;
    dispatch_function_t     doFinalize;
};

// dispatch_item

typedef struct dispatch_item_s*     dispatch_item_t;
struct dispatch_item_s {
    dispatch_item_t         next;
    dispatch_function_t     function;
    void*                   context;
};

// dispatch_simple_item

typedef struct {
    dispatch_function_t     function;
    void*                   context;

}   dispatch_simple_item;

// dispatch_queue

#define kDispatchQueue_MagicGood        0x64717565  // 'dque'
#define kDispatchQueue_MagicBad         0x44515545  // 'DQUE'
#define DispatchQueueValid( OBJ )   \
    ( ( OBJ ) && ( ( OBJ )->base.magic == kDispatchQueue_MagicGood ) && ( ( OBJ )->base.refCount > 0 ) )

struct dispatch_queue_s {
    struct dispatch_base_s      base;
    pthread_mutex_t             lock;
    pthread_mutex_t*            lockPtr;
    dispatch_item_t             itemsHead;
    dispatch_item_t*            itemsNext;  // Address of last element's next field. Never NULL.
    Boolean                     busy;       // true if currently draining the queue.
    Boolean                     pending;    // true if a drain request is pending.
    Boolean                     concurrent;
    int32_t                     suspendCount;
    char                        label[ 64 ];
    int                         priority;
};

// dispatch_source

#define kDispatchSource_MagicGood               0x64737263  // 'dsrc'
#define kDispatchSource_MagicBad                0x44535243  // 'DSRC'
#define DispatchSourceValidOrFreeing( OBJ )     ( ( OBJ ) && ( ( OBJ )->base.magic == kDispatchSource_MagicGood ) )

#define DispatchSourceValid( OBJ )      \
    ( ( OBJ ) && ( ( OBJ )->base.magic == kDispatchSource_MagicGood ) && ( ( OBJ )->base.refCount > 0 ) )

struct dispatch_source_s {
    struct dispatch_base_s      base;
    int32_t                     suspendCount;
    dispatch_queue_t            queue;
    Boolean                     canceled;
    Boolean                     started;            // Registered with kqueue at least once before.
    int32_t                     pending;            // 1 if a callback is currently pending.
    dispatch_function_t         handlerFunction;
    dispatch_function_t         cancelFunction;
    dispatch_source_type_t      type;
#if( DISPATCH_LITE_USE_SELECT )
    dispatch_source_t           armedNext;
#endif
    union {
        // Read/Write

        struct {
            SocketRef           fd;
#if( TARGET_OS_WINDOWS )
            Boolean         fdTracked;
#endif
            size_t              avail;

        }   rw;

        // Signals

        struct {
            unsigned long       sig;

        }   sig;

        // Timers

        struct {
            dispatch_time_t     start;
            uint64_t            intervalMs;
            unsigned long       count;
#if( DISPATCH_LITE_USE_SELECT )
            uint64_t        expireTicks;
#elif( TARGET_OS_WINDOWS )
            HANDLE          timer;
#endif

        }   timer;

    }   u;
};

// dispatch_select_packet

#if( DISPATCH_LITE_USE_SELECT )

#define kDispatchCommandArmSource           1
#define kDispatchCommandDisarmSource        2
#define kDispatchCommandFreeSource          3
#define kDispatchCommandQuit                4

typedef struct {
    uint8_t                 cmd;
    dispatch_source_t       source;

}   dispatch_select_packet;

#endif

// dispatch_semaphore

struct dispatch_semaphore_s {
    struct dispatch_base_s      base;
    pthread_mutex_t             mutex;
    pthread_mutex_t*            mutexPtr;
    pthread_cond_t              condition;
    pthread_cond_t*             conditionPtr;
    long                        value;
};

// DispatchSocketHashEntry

#if( TARGET_OS_WINDOWS )
typedef struct DispatchSocketHashEntry*         DispatchSocketHashRef;
struct DispatchSocketHashEntry {
    DispatchSocketHashRef       next;
    SOCKET                      sock;
    dispatch_source_t           source;
};
#endif

// dispatch_union

typedef union {
    struct dispatch_base_s          base;
    struct dispatch_queue_s         queue;
    struct dispatch_source_s        source;
    struct dispatch_semaphore_s     sem;

}   dispatch_union;

#if 0
#pragma mark == Prototypes ==
#endif

//===========================================================================================================================
//  Prototypes
//===========================================================================================================================

DEBUG_STATIC OSStatus       __LibDispatch_ScheduleWork(dispatch_function_t inFunction, void* inContext);
#if( !TARGET_OS_WINDOWS )
DEBUG_STATIC void*      __LibDispatch_WorkThread(void* inArg);
#endif
DEBUG_STATIC void           __dispatch_empty_callback(void* inContext);

// Objects

DEBUG_STATIC void   __dispatch_free_object(dispatch_object_t inObj);

// Queues

DEBUG_STATIC dispatch_queue_t   __dispatch_queue_create_internal(const char* inLabel);
DEBUG_STATIC void               __dispatch_queue_free(void* inArg);
DEBUG_STATIC void               __dispatch_queue_suspend(dispatch_queue_t inQueue);
DEBUG_STATIC void               __dispatch_queue_resume(dispatch_queue_t inQueue);
DEBUG_STATIC void               __dispatch_queue_concurrent_drain(void* inContext);
DEBUG_STATIC void               __dispatch_queue_serial_drain(void* inContext);
DEBUG_STATIC void               __dispatch_queue_serial_drain_locked(dispatch_queue_t inQueue);

// Sources

DEBUG_STATIC void   __dispatch_source_suspend(dispatch_source_t inSource);
DEBUG_STATIC void   __dispatch_source_resume(dispatch_source_t inSource);
DEBUG_STATIC void   __dispatch_source_free(void* inContext);

// Time

DEBUG_STATIC uint64_t   __dispatch_milliseconds(void);
DEBUG_STATIC uint64_t   __dispatch_wall_milliseconds(void);

// CF Support

#if( DISPATCH_LITE_CF_ENABLED )
DEBUG_STATIC OSStatus       __LibDispatchCF_EnsureInitialized(void);
DEBUG_STATIC void           __LibDispatchCF_Finalize(void);
DEBUG_STATIC OSStatus       __LibDispatchCF_Schedule(void);
DEBUG_STATIC void           __LibDispatchCF_SourcePerform(void* inContext);
#endif

// Platform Support

DEBUG_STATIC void   __LibDispatch_PlatformFreeSource(void* inArg);
DEBUG_STATIC void   __LibDispatch_PlatformArmSourceAndUnlock(dispatch_source_t inSource);
DEBUG_STATIC void   __LibDispatch_PlatformDisarmSourceAndUnlock(dispatch_source_t inSource);

// KQueue Support

#if( DISPATCH_LITE_USE_KQUEUE )
DEBUG_STATIC int        __LibDispatch_GetKQueue(void);
DEBUG_STATIC OSStatus   __LibDispatch_KQueueDispatchAsync(dispatch_function_t inFunction, void* inContext);
DEBUG_STATIC void       __LibDispatch_KQueueDrain(void* inContext);
DEBUG_STATIC void       __LibDispatch_KQueueFDEvent(void* inContext);
DEBUG_STATIC void       __LibDispatch_KQueueSignalEvent(void* inContext);
DEBUG_STATIC void       __LibDispatch_KQueueTimerEvent(void* inContext);
#endif

// Select Support

#if( DISPATCH_LITE_USE_SELECT )
DEBUG_STATIC OSStatus   __LibDispatch_SelectEnsureInitialized(void);
DEBUG_STATIC void       __LibDispatch_SelectDrain(void* inArg);
DEBUG_STATIC OSStatus   __LibDispatch_SelectHandleCommand(const dispatch_select_packet* inPkt);
DEBUG_STATIC void       __LibDispatch_SelectHandleReadWriteEvent(void* inContext);
DEBUG_STATIC void       __LibDispatch_SelectHandleTimerEvent(void* inContext);
DEBUG_STATIC void       __LibDispatch_PlatformArmOrDisarmSourceAndUnlock(dispatch_source_t inSource, uint8_t inCmd);
#endif

// Windows Support

#if( TARGET_OS_WINDOWS )
DEBUG_STATIC LRESULT CALLBACK   __LibDispatch_MainQueueWinProc(HWND inWindow, UINT inMsg, WPARAM inWParam,
                                                               LPARAM inLParam);
DEBUG_STATIC OSStatus           __LibDispatch_IOThreadStart(void);
DEBUG_STATIC void               __LibDispatch_IOThreadStop(void);
DEBUG_STATIC void*              __LibDispatch_IOThread(void* inArg);
DEBUG_STATIC LRESULT CALLBACK   __LibDispatch_IOThreadWinProc(HWND inWindow, UINT inMsg, WPARAM inWParam,
                                                              LPARAM inLParam);
#define                         __LibDispatch_AddSocket( SOCK, SOURCE )     __LibDispatch_LookupSocket( ( SOCK ), ( SOURCE ), NULL )
#define                         __LibDispatch_RemoveSocket( SOCK )          __LibDispatch_LookupSocket( ( SOCK ), NULL, NULL )
DEBUG_STATIC OSStatus           __LibDispatch_LookupSocket(SOCKET inSock, dispatch_source_t inSource,
                                                           dispatch_source_t* outSource);

DEBUG_STATIC void               __LibDispatch_WindowsSocketEvent(void* inContext);
DEBUG_STATIC void CALLBACK      __LibDispatch_WindowsTimerCallBack(void* inArg, BOOLEAN inFired);
DEBUG_STATIC void               __LibDispatch_WindowsTimerEvent(void* inContext);
#endif

#if 0
#pragma mark == Globals ==
#endif

//===========================================================================================================================
//  Globals
//===========================================================================================================================

static Boolean                      gDispatchInitialized                = false;
static pthread_mutex_t              gDispatchInitializeMutex            = PTHREAD_MUTEX_INITIALIZER;

// Thread Pool

#if( !TARGET_OS_WINDOWS )
static pthread_mutex_t          gDispatchThreadPool_Mutex;
static pthread_mutex_t*         gDispatchThreadPool_MutexPtr        = NULL;
static pthread_cond_t           gDispatchThreadPool_Condition;
static pthread_cond_t*          gDispatchThreadPool_ConditionPtr    = NULL;
static pthread_attr_t           gDispatchThreadPool_Attr;
static pthread_attr_t*          gDispatchThreadPool_AttrPtr         = NULL;
static int                      gDispatchThreadPool_CurrentThreads  = 0;
static int                      gDispatchThreadPool_IdleThreads     = 0;
static int                      gDispatchThreadPool_MaxThreads      = 128;
static dispatch_item_t          gDispatchThreadPool_ItemsHead       = NULL;
static dispatch_item_t*         gDispatchThreadPool_ItemsNext       = NULL;
static int                      gDispatchThreadPool_PendingItems    = 0;
static Boolean                  gDispatchThreadPool_Quit            = false;
#endif

// Globals Queues

static pthread_key_t                gDispatchKey_CurrentQueue;
static pthread_key_t*               gDispatchKey_CurrentQueuePtr        = NULL;
static dispatch_queue_t             gDispatchConcurrentQueues[ 3 ]      = { NULL, NULL, NULL };

static dispatch_queue_t             gDispatchMainQueue                  = NULL;
dispatch_function_t                 gDispatchMainQueueScheduleHookFunc  = NULL;

#if( !TARGET_OS_WINDOWS )
static pthread_cond_t           gDispatchMainQueue_Condition;
static pthread_cond_t*          gDispatchMainQueue_ConditionPtr     = NULL;
static Boolean                  gDispatchMainQueue_WorkPending      = false;
#endif

// CF Support

#if( DISPATCH_LITE_CF_ENABLED )
static Boolean                  gDispatchCFInitialized              = false;
static CFRunLoopRef             gDispatchCF_MainRL                  = NULL;
static CFRunLoopSourceRef       gDispatchCF_Source                  = NULL;
#endif

// KQueue Support

#if( DISPATCH_LITE_USE_KQUEUE )
static pthread_mutex_t          gDispatchKQueue_Mutex;
static pthread_mutex_t*         gDispatchKQueue_MutexPtr            = NULL;
static int32_t                  gDispatchKQueue_FD                  = -1;
static int32_t                  gDispatchKQueue_PipeSend            = -1;
static int32_t                  gDispatchKQueue_PipeRecv            = -1;
static dispatch_queue_t         gDispatchKQueue_DrainQueue          = NULL;
#endif

// Select Support

#if( DISPATCH_LITE_USE_SELECT )
static dispatch_queue_t         gDispatchSelect_CommandQueue        = NULL;
static FDRef                    gDispatchSelect_CommandReadFD       = kInvalidFD;
static FDRef                    gDispatchSelect_CommandWriteFD      = kInvalidFD;
static dispatch_source_t        gDispatchSelect_ReadWriteList       = NULL;
static fd_set                   gDispatchSelect_ReadSet;
static fd_set                   gDispatchSelect_WriteSet;
static dispatch_source_t        gDispatchSelect_TimerList           = NULL;
static dispatch_semaphore_t     gDispatchSelect_QuitSem             = NULL;
#endif

// Windows Support

#if( TARGET_OS_WINDOWS )
static LONG                     gDispatchConcurrentCount            = 0;
static LONG                     gDispatchSerialCount                = 0;

static HWND                     gDispatchMainQueueWindow            = NULL;

static pthread_t                gDispatchIOThread;
static pthread_t*               gDispatchIOThreadPtr                = NULL;
static HWND                     gDispatchIOThreadWindow             = NULL;
static DispatchSocketHashRef    gDispatchSocketHashTable[ 61 ];
static pthread_mutex_t          gDispatchSocketHashTableMutex;
static pthread_mutex_t*         gDispatchSocketHashTableMutexPtr    = NULL;

static Boolean                  gDispatchDidWSAStartup              = false;
#endif

dlog_define(gcd, kLogLevelNotice, kLogFlags_Default, "gcd", NULL);
#if( TARGET_HAS_C99_VA_ARGS )
#define gcd_ulog( LEVEL, ... )      dlogc( &log_category_from_name( gcd ), (LEVEL), __VA_ARGS__ )
#else
#define gcd_ulog( LEVEL, ARGS... )  dlogc( &log_category_from_name( gcd ), (LEVEL), ## ARGS )
#endif

#if 0
#pragma mark == General ==
#endif

//===========================================================================================================================
//  LibDispatch_EnsureInitialized
//
//  Note: Must be called from the main thread.
//===========================================================================================================================

OSStatus    LibDispatch_EnsureInitialized(void) {
    OSStatus        err;

    pthread_mutex_lock(&gDispatchInitializeMutex);
    require_action_quiet(!gDispatchInitialized, exit, err = kNoErr);

    // Set up thread pool.

#if( !TARGET_OS_WINDOWS )
    gDispatchThreadPool_Quit = false;

    err = pthread_mutex_init(&gDispatchThreadPool_Mutex, NULL);
    require_noerr(err, exit);
    gDispatchThreadPool_MutexPtr = &gDispatchThreadPool_Mutex;

    pthread_condattr_t condattr;
    pthread_condattr_init(&condattr);
    err = pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
    require_noerr(err, exit);

    err = pthread_cond_init(&gDispatchThreadPool_Condition, &condattr);
    pthread_condattr_destroy(&condattr);
    require_noerr(err, exit);
    gDispatchThreadPool_ConditionPtr = &gDispatchThreadPool_Condition;

    err = pthread_attr_init(&gDispatchThreadPool_Attr);
    require_noerr(err, exit);
    gDispatchThreadPool_AttrPtr = &gDispatchThreadPool_Attr;

    err = pthread_attr_setdetachstate(gDispatchThreadPool_AttrPtr, PTHREAD_CREATE_DETACHED);
    require_noerr(err, exit);

    gDispatchThreadPool_ItemsHead = NULL;
    gDispatchThreadPool_ItemsNext = &gDispatchThreadPool_ItemsHead;
#endif

    // Set up global queues.

    err = pthread_key_create(&gDispatchKey_CurrentQueue, NULL);
    require_noerr(err, exit);
    gDispatchKey_CurrentQueuePtr = &gDispatchKey_CurrentQueue;

    gDispatchConcurrentQueues[ 0 ] = __dispatch_queue_create_internal("com.apple.low-priority-root-queue");
    require_action(gDispatchConcurrentQueues[ 0 ], exit, err = ENOMEM);
    gDispatchConcurrentQueues[ 0 ]->concurrent = true;

    gDispatchConcurrentQueues[ 1 ] = __dispatch_queue_create_internal("com.apple.root-queue");
    require_action(gDispatchConcurrentQueues[ 1 ], exit, err = ENOMEM);
    gDispatchConcurrentQueues[ 1 ]->concurrent = true;

    gDispatchConcurrentQueues[ 2 ] = __dispatch_queue_create_internal("com.apple.high-priority-root-queue");
    require_action(gDispatchConcurrentQueues[ 2 ], exit, err = ENOMEM);
    gDispatchConcurrentQueues[ 2 ]->concurrent = true;

    // Set up the main queue.

#if( !TARGET_OS_WINDOWS )
    gDispatchMainQueue_WorkPending = false;
#endif

    gDispatchMainQueue = __dispatch_queue_create_internal("com.apple.main-queue");
    require_action(gDispatchMainQueue, exit, err = ENOMEM);

#if( !TARGET_OS_WINDOWS )
    err = pthread_cond_init(&gDispatchMainQueue_Condition, NULL);
    require_noerr(err, exit);
    gDispatchMainQueue_ConditionPtr = &gDispatchMainQueue_Condition;
#endif

    pthread_setspecific(gDispatchKey_CurrentQueue, gDispatchMainQueue);

    // Set up kqueue support.

#if( DISPATCH_LITE_USE_KQUEUE )
    err = pthread_mutex_init(&gDispatchKQueue_Mutex, NULL);
    require_noerr(err, exit);
    gDispatchKQueue_MutexPtr = &gDispatchKQueue_Mutex;

    gDispatchKQueue_DrainQueue = __dispatch_queue_create_internal("com.apple.kqueue-drain");
    require_action(gDispatchKQueue_DrainQueue, exit, err = ENOMEM);
#endif

    // Set up CF support.

#if( DISPATCH_LITE_CF_ENABLED )
    err = __LibDispatchCF_EnsureInitialized();
    require_noerr(err, exit);
#endif

    // Set up select() support.

#if( DISPATCH_LITE_USE_SELECT )
    err = __LibDispatch_SelectEnsureInitialized();
    require_noerr(err, exit);
#endif

    // Set up Windows support.

#if( TARGET_OS_WINDOWS )
    {
        HINSTANCE       instance;
        WNDCLASSEX      wcex;
        HWND            wind;
        WSADATA         wsaData;

        gDispatchConcurrentCount = 0;
        gDispatchSerialCount     = 0;

        instance = GetModuleHandle(NULL);
        err = map_global_value_errno(instance, instance);
        require_noerr(err, exit);

        wcex.cbSize         = sizeof(wcex);
        wcex.style          = 0;
        wcex.lpfnWndProc    = __LibDispatch_MainQueueWinProc;
        wcex.cbClsExtra     = 0;
        wcex.cbWndExtra     = 0;
        wcex.hInstance      = instance;
        wcex.hIcon          = NULL;
        wcex.hCursor        = NULL;
        wcex.hbrBackground  = NULL;
        wcex.lpszMenuName   = NULL;
        wcex.lpszClassName  = TEXT("libdispatch_main");
        wcex.hIconSm        = NULL;
        RegisterClassEx(&wcex);

        wind = CreateWindow(wcex.lpszClassName, wcex.lpszClassName, 0, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL,
                            instance, NULL);
        err = map_global_value_errno(wind, wind);
        require_noerr(err, exit);
        gDispatchMainQueueWindow = wind;

        // Set up handling of IO.

        err = WSAStartup(MAKEWORD(2, 2), &wsaData);
        check_noerr(err);
        gDispatchDidWSAStartup = true;

        err = pthread_mutex_init(&gDispatchSocketHashTableMutex, NULL);
        require_noerr(err, exit);
        gDispatchSocketHashTableMutexPtr = &gDispatchSocketHashTableMutex;

        err = __LibDispatch_IOThreadStart();
        require_noerr(err, exit);
    }
#endif // TARGET_OS_WINDOWS

    gDispatchInitialized = true;

exit:
    pthread_mutex_unlock(&gDispatchInitializeMutex);
    if (err) {
        LibDispatch_Finalize();
    }
    return (err);
}

//===========================================================================================================================
//  LibDispatch_Finalize
//===========================================================================================================================

void    LibDispatch_Finalize(void) {
    OSStatus        err;
    size_t          i;

    DEBUG_USE_ONLY(err);

    // Tear down CF support.

#if( DISPATCH_LITE_CF_ENABLED )
    __LibDispatchCF_Finalize();
#endif

    // Tear down kqueue support.

#if( DISPATCH_LITE_USE_KQUEUE )
    if (gDispatchKQueue_DrainQueue) {
        // Tells the kqueue thread to quit then force a synchronous empty callback to wait for it to finish.

        if (gDispatchKQueue_PipeSend >= 0) {
            __LibDispatch_KQueueDispatchAsync(NULL, NULL);
        }
        dispatch_sync_f(gDispatchKQueue_DrainQueue, NULL, __dispatch_empty_callback);
        dispatch_release(gDispatchKQueue_DrainQueue);
        gDispatchKQueue_DrainQueue = NULL;
    }
    ForgetFD(&gDispatchKQueue_FD);
    ForgetFD(&gDispatchKQueue_PipeSend);
    ForgetFD(&gDispatchKQueue_PipeRecv);
    pthread_mutex_forget(&gDispatchKQueue_MutexPtr);
#endif

    // Tear down select() support.

#if( DISPATCH_LITE_USE_SELECT )
    if (IsValidSocket(gDispatchSelect_CommandWriteFD)) {
        dispatch_select_packet      pkt;
        ssize_t                     n;

        check(gDispatchSelect_QuitSem == NULL);
        gDispatchSelect_QuitSem = dispatch_semaphore_create(0);
        check(gDispatchSelect_QuitSem);

        pkt.cmd     = kDispatchCommandQuit;
        pkt.source  = NULL;
        n = write(gDispatchSelect_CommandWriteFD, &pkt, sizeof(pkt));
        err = map_global_value_errno(n == (ssize_t) sizeof(pkt), n);
        check_noerr(err);

        if (gDispatchSelect_QuitSem) {
            dispatch_semaphore_wait(gDispatchSelect_QuitSem, DISPATCH_TIME_FOREVER);
            dispatch_release(gDispatchSelect_QuitSem);
            gDispatchSelect_QuitSem = NULL;
        }
    }
    dispatch_forget(&gDispatchSelect_CommandQueue);
    ForgetFD(&gDispatchSelect_CommandReadFD);
    ForgetFD(&gDispatchSelect_CommandWriteFD);
    check(gDispatchSelect_ReadWriteList == NULL);
    check(gDispatchSelect_TimerList == NULL);
    check(gDispatchSelect_QuitSem == NULL);
#endif

    // Tear down Windows support.

#if( TARGET_OS_WINDOWS )
    __LibDispatch_IOThreadStop();
    pthread_mutex_forget(&gDispatchSocketHashTableMutexPtr);
    if (gDispatchMainQueueWindow) {
        BOOL        good;

        good = DestroyWindow(gDispatchMainQueueWindow);
        err = map_global_value_errno(good, good);
        check_noerr(err);
        gDispatchMainQueueWindow = NULL;
    }
    if (gDispatchDidWSAStartup) {
        gDispatchDidWSAStartup = false;
        WSACleanup();
    }
#endif

    // Tear down the main queue.

#if( TARGET_OS_WINDOWS )
    while (InterlockedCompareExchange(&gDispatchSerialCount, 0, 0) != 0) {
        // Cheesy to use a sleep loop like this, but the only alternative I could think of is to use a pthread
        // mutex and conditional variable to signal each time the thread is done because we're using the Windows
        // thread pool API and don't have direct access to the thread. The only time this sleep loop is used is
        // when finalizing the entire libdispatch library and since that usually only happens once at app quit,
        // if it even happens at all, I opt'd for the lower overhead, but somewhat cheesy sleep loop.

        Sleep(1);
    }
#endif
    dispatch_forget(&gDispatchMainQueue);
#if( !TARGET_OS_WINDOWS )
    pthread_cond_forget(&gDispatchMainQueue_ConditionPtr);
#endif

    // Tear down global queues.

#if( TARGET_OS_WINDOWS )
    while (InterlockedCompareExchange(&gDispatchConcurrentCount, 0, 0) != 0) {
        // Cheesy to use a sleep loop like this, but the only alternative I could think of is to use a pthread
        // mutex and conditional variable to signal each time the thread is done because we're using the Windows
        // thread pool API and don't have direct access to the thread. The only time this sleep loop is used is
        // when finalizing the entire libdispatch library and since that usually only happens once at app quit,
        // if it even happens at all, I opt'd for the lower overhead, but somewhat cheesy sleep loop.

        Sleep(1);
    }
#else
    for (i = 0; i < countof(gDispatchConcurrentQueues); ++i) {
        if (gDispatchConcurrentQueues[ i ]) {
            dispatch_sync_f(gDispatchConcurrentQueues[ i ], NULL, __dispatch_empty_callback);
        }
    }
#endif
    for (i = 0; i < countof(gDispatchConcurrentQueues); ++i) {
        dispatch_forget(&gDispatchConcurrentQueues[ i ]);
    }
    if (gDispatchKey_CurrentQueuePtr) {
        err = pthread_key_delete(gDispatchKey_CurrentQueue);
        check_noerr(err);
        gDispatchKey_CurrentQueuePtr = NULL;
    }

    // Tear down thread pool.

#if( !TARGET_OS_WINDOWS )
    if (gDispatchThreadPool_MutexPtr) {
        pthread_mutex_lock(gDispatchThreadPool_MutexPtr);
        gDispatchThreadPool_Quit = true;
#if( TARGET_NO_PTHREAD_BROADCAST )
        while (gDispatchThreadPool_CurrentThreads > 0) {
            err = pthread_cond_signal(gDispatchThreadPool_ConditionPtr);
            check_noerr(err);

            pthread_mutex_unlock(gDispatchThreadPool_MutexPtr);
            usleep(50000);   // Cheesy, but probably not worth a quit condition.
            pthread_mutex_lock(gDispatchThreadPool_MutexPtr);
        }
#else
        if (gDispatchThreadPool_CurrentThreads > 0) {
            if (gDispatchThreadPool_IdleThreads > 0) {
                err = pthread_cond_broadcast(gDispatchThreadPool_ConditionPtr);
                check_noerr(err);
            }
            while (gDispatchThreadPool_CurrentThreads > 0) {
                err = pthread_cond_wait(gDispatchThreadPool_ConditionPtr, gDispatchThreadPool_MutexPtr);
                check_noerr(err);
            }
        }
#endif
        pthread_mutex_unlock(gDispatchThreadPool_MutexPtr);
    }
    check(gDispatchThreadPool_ItemsHead == NULL);
    check(gDispatchThreadPool_PendingItems == 0);

    if (gDispatchThreadPool_AttrPtr) {
        pthread_attr_destroy(gDispatchThreadPool_AttrPtr);
        gDispatchThreadPool_AttrPtr = NULL;
    }
    pthread_cond_forget(&gDispatchThreadPool_ConditionPtr);
    pthread_mutex_forget(&gDispatchThreadPool_MutexPtr);
#endif

    gDispatchInitialized = false;
}

//===========================================================================================================================
//  __LibDispatch_ScheduleWork
//===========================================================================================================================

#if( TARGET_OS_WINDOWS )
DEBUG_STATIC DWORD WINAPI   __LibDispatch_ScheduleWorkWrapper(void* inArg);

DEBUG_STATIC OSStatus   __LibDispatch_ScheduleWork(dispatch_function_t inFunction, void* inContext) {
    OSStatus            err;
    dispatch_item_t     item;
    BOOL                good;

    item = (dispatch_item_t) malloc(sizeof(*item));
    require_action(item, exit, err = kNoMemoryErr);
    item->function = inFunction;
    item->context  = inContext;

    good = QueueUserWorkItem(__LibDispatch_ScheduleWorkWrapper, item, WT_EXECUTEDEFAULT);
    err = map_global_value_errno(good, good);
    require_noerr(err, exit);
    item = NULL;

exit:
    if (item) {
        free(item);
    }
    return (err);
}

DEBUG_STATIC DWORD WINAPI   __LibDispatch_ScheduleWorkWrapper(void* inArg) {
    dispatch_item_t const       item = (dispatch_item_t) inArg;

    item->function(item->context);
    free(item);
    return (0);
}
#else // !TARGET_OS_WINDOWS
DEBUG_STATIC OSStatus   __LibDispatch_ScheduleWork(dispatch_function_t inFunction, void* inContext) {
    OSStatus            err;
    dispatch_item_t     item;
    pthread_t           tid;

    item = (dispatch_item_t) calloc(1, sizeof(*item));
    require_action(item, exit2, err = kNoMemoryErr);
    item->function = inFunction;
    item->context  = inContext;

    pthread_mutex_lock(gDispatchThreadPool_MutexPtr);

    *gDispatchThreadPool_ItemsNext = item;
    gDispatchThreadPool_ItemsNext = &item->next;
    ++gDispatchThreadPool_PendingItems;

    // If there's already an idle thread, signal one that more work is available.

    if (gDispatchThreadPool_IdleThreads > 0) {
        err = pthread_cond_signal(gDispatchThreadPool_ConditionPtr);
        check_noerr(err);
    }

    // If we have more work than threads and we haven't hit our max threads, create a new thread.

    if (gDispatchThreadPool_IdleThreads < gDispatchThreadPool_PendingItems) {
        if (gDispatchThreadPool_CurrentThreads < gDispatchThreadPool_MaxThreads) {
            err = pthread_create(&tid, gDispatchThreadPool_AttrPtr, __LibDispatch_WorkThread, NULL);
            require_noerr(err, exit);

            ++gDispatchThreadPool_CurrentThreads;
            gcd_ulog(kLogLevelChatty, "+++ created work thread: %d now (%d max)\n",
                     gDispatchThreadPool_CurrentThreads, gDispatchThreadPool_MaxThreads);
        }
        else {
            gcd_ulog(kLogLevelNotice, "*** more work, but not allowed to create another thread (%d of %d)\n",
                     gDispatchThreadPool_CurrentThreads, gDispatchThreadPool_MaxThreads);
        }
    }
    err = kNoErr;

exit:
    pthread_mutex_unlock(gDispatchThreadPool_MutexPtr);

exit2:
    return (err);
}
#endif // TARGET_OS_WINDOWS

//===========================================================================================================================
//  __LibDispatch_WorkThread
//===========================================================================================================================

#if( !TARGET_OS_WINDOWS )
DEBUG_STATIC void*  __LibDispatch_WorkThread(void* inArg) {
    OSStatus            err;
    Boolean             timedOut;
    dispatch_item_t     item;
    struct timespec     timeout;

    (void) inArg; // Unused

    pthread_setname_np_compat("gcd-work");
    pthread_mutex_lock(gDispatchThreadPool_MutexPtr);
    for (;;) {
        // Wait for work or timeout if we're idle for too long.

#if( TARGET_OS_THREADX )
        timeout.tv_sec  = 2;
        timeout.tv_nsec = 0;
        timedOut = false;
        while ((gDispatchThreadPool_ItemsHead == NULL) && !gDispatchThreadPool_Quit) {
            ++gDispatchThreadPool_IdleThreads;
            err = pthread_cond_timedwait_relative_np(gDispatchThreadPool_ConditionPtr, gDispatchThreadPool_MutexPtr,
                                                     &timeout);
            --gDispatchThreadPool_IdleThreads;
            if (err == ETIMEDOUT) {
                timedOut = true;
                break;
            }
            check_noerr(err);
        }
#else
        clock_gettime(CLOCK_MONOTONIC, &timeout);
        timeout.tv_sec += 2;
        timedOut = false;
        while ((gDispatchThreadPool_ItemsHead == NULL) && !gDispatchThreadPool_Quit) {
            ++gDispatchThreadPool_IdleThreads;
            err = pthread_cond_timedwait(gDispatchThreadPool_ConditionPtr, gDispatchThreadPool_MutexPtr, &timeout);
            --gDispatchThreadPool_IdleThreads;
            if (err == ETIMEDOUT) {
                timedOut = true;
                break;
            }
            check_noerr(err);
        }
#endif

        // Process the next item (if any).

        item = gDispatchThreadPool_ItemsHead;
        if (item) {
            timedOut = false;

            if ((gDispatchThreadPool_ItemsHead = item->next) == NULL) {
                gDispatchThreadPool_ItemsNext = &gDispatchThreadPool_ItemsHead;
            }
            --gDispatchThreadPool_PendingItems;

            pthread_mutex_unlock(gDispatchThreadPool_MutexPtr);
            item->function(item->context);
            free(item);
            pthread_mutex_lock(gDispatchThreadPool_MutexPtr);
        }

        // Exit if there's no more work and we're quitting.

        item = gDispatchThreadPool_ItemsHead;
        if ((item == NULL) && gDispatchThreadPool_Quit) {
            // If we're last thread to go away, tell the delete function.

            if (--gDispatchThreadPool_CurrentThreads == 0) {
#if( !TARGET_NO_PTHREAD_BROADCAST )
                err = pthread_cond_broadcast(gDispatchThreadPool_ConditionPtr);
                check_noerr(err);
#endif
            }
            gcd_ulog(kLogLevelNotice, "--- quitting thread: %d now (%d max)\n",
                     gDispatchThreadPool_CurrentThreads, gDispatchThreadPool_MaxThreads);
            break;
        }

        // Exit if there's no more work and we timed out.

        if ((item == NULL) && timedOut) {
            --gDispatchThreadPool_CurrentThreads;
            gcd_ulog(kLogLevelChatty, "--- aging idle thread: %d now (%d max)\n",
                     gDispatchThreadPool_CurrentThreads, gDispatchThreadPool_MaxThreads);
            break;
        }
    }
    pthread_mutex_unlock(gDispatchThreadPool_MutexPtr);
    return (NULL);
}
#endif // !TARGET_OS_WINDOWS

#if 0
#pragma mark -
#endif

//===========================================================================================================================
//  __dispatch_free_object
//===========================================================================================================================

DEBUG_STATIC void   __dispatch_free_object(dispatch_object_t inObj) {
    dispatch_union* const          obj     = (dispatch_union*) inObj;
    dispatch_function_t const       func    = obj->base.doFinalize;
    void* const                    context = obj->base.context;

    free(inObj);
    if (func) {
        func(context);
    }
}

//===========================================================================================================================
//  dispatch_retain
//===========================================================================================================================

void    dispatch_retain(dispatch_object_t inObj) {
    dispatch_union* const      obj = (dispatch_union*) inObj;

    require(obj, exit);

    atomic_add_32(&obj->base.refCount, 1);

exit:
    return;
}

//===========================================================================================================================
//  dispatch_release
//===========================================================================================================================

void    dispatch_release(dispatch_object_t inObj) {
    dispatch_union* const      obj = (dispatch_union*) inObj;

    require(obj, exit);

    if (atomic_add_and_fetch_32(&obj->base.refCount, -1) == 0) {
        check(obj->base.doFree);
        obj->base.doFree(inObj);
    }

exit:
    return;
}

//===========================================================================================================================
//  dispatch_get_context
//===========================================================================================================================

void*   dispatch_get_context(dispatch_object_t inObj) {
    return (((const dispatch_union*) inObj)->base.context);
}

//===========================================================================================================================
//  dispatch_set_context
//===========================================================================================================================

void    dispatch_set_context(dispatch_object_t inObj, void* inContext) {
    ((dispatch_union*) inObj)->base.context = inContext;
}

//===========================================================================================================================
//  dispatch_set_finalizer_f
//===========================================================================================================================

void    dispatch_set_finalizer_f(dispatch_object_t inObj, dispatch_function_t inFinalizer) {
    ((dispatch_union*) inObj)->base.doFinalize = inFinalizer;
}

//===========================================================================================================================
//  dispatch_suspend
//===========================================================================================================================

void    dispatch_suspend(dispatch_object_t inObj) {
    uint32_t        magic;

    require(inObj, exit);
    magic = *((const uint32_t*) inObj);
    if (magic == kDispatchQueue_MagicGood) {
        __dispatch_queue_suspend((dispatch_queue_t) inObj);
    }
    else if (magic == kDispatchSource_MagicGood) {
        __dispatch_source_suspend((dispatch_source_t) inObj);
    }
    else {
        dlogassert("bad object '%C' %p", magic, inObj);
        goto exit;
    }

exit:
    return;
}

//===========================================================================================================================
//  dispatch_resume
//===========================================================================================================================

void    dispatch_resume(dispatch_object_t inObj) {
    uint32_t        magic;

    require(inObj, exit);
    magic = *((const uint32_t*) inObj);
    if (magic == kDispatchQueue_MagicGood) {
        __dispatch_queue_resume((dispatch_queue_t) inObj);
    }
    else if (magic == kDispatchSource_MagicGood) {
        __dispatch_source_resume((dispatch_source_t) inObj);
    }
    else {
        dlogassert("bad object '%C' %p", magic, inObj);
        goto exit;
    }

exit:
    return;
}

#if 0
#pragma mark -
#endif

//===========================================================================================================================
//  dispatch_after_f
//===========================================================================================================================

typedef struct {
    dispatch_source_t       timer;
    dispatch_function_t     user_f;
    void*                   user_ctx;

}   dispatch_after_context;

static void dispatch_after_handler(void* inContext);

void    dispatch_after_f(dispatch_time_t inWhen, dispatch_queue_t inQueue, void* inContext,
                         dispatch_function_t inFunction) {
    dispatch_time_t                 nowDT;
    uint64_t                        nanos;
    dispatch_after_context*         ctx = NULL;

    if (inWhen == DISPATCH_TIME_FOREVER) {
        dlogassert("### dispatch_after_f with DISPATCH_TIME_FOREVER will never run");
        goto exit;
    }
    if (inWhen == 0) {
        dispatch_async_f(inQueue, inContext, inFunction);
        goto exit;
    }

    // Calculate the nanoseconds until the deadline.

    if (((int64_t) inWhen) < 0) {  // Negative if wall clock time.
        inWhen  = (dispatch_time_t)(-((int64_t) inWhen));
        nowDT   = (dispatch_time_t)(-((int64_t) dispatch_walltime(NULL, 0)));
    }
    else {
        nowDT = dispatch_time(DISPATCH_TIME_NOW, 0);
    }
    nanos = (uint64_t)((nowDT < inWhen) ? (kNanosecondsPerMillisecond * (inWhen - nowDT)) : 0);

    // Start a timer to call the function at the deadline.

    ctx = (dispatch_after_context*) calloc(1, sizeof(*ctx));
    require(ctx, exit);
    ctx->user_f     = inFunction;
    ctx->user_ctx   = inContext;

    ctx->timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, inQueue);
    require(ctx->timer, exit);
    dispatch_set_context(ctx->timer, ctx);
    dispatch_source_set_event_handler_f(ctx->timer, dispatch_after_handler);
    dispatch_source_set_timer(ctx->timer, dispatch_time(DISPATCH_TIME_NOW, (int64_t) nanos), DISPATCH_TIME_FOREVER,
                              nanos / 10);
    dispatch_resume(ctx->timer);
    ctx = NULL;

exit:
    FreeNullSafe(ctx);
}

//===========================================================================================================================
//  dispatch_after_handler
//===========================================================================================================================

static void dispatch_after_handler(void* inContext) {
    dispatch_after_context* const      ctx = (dispatch_after_context*) inContext;

    dispatch_source_forget(&ctx->timer);
    ctx->user_f(ctx->user_ctx);
    free(ctx);
}

//===========================================================================================================================
//  dispatch_async
//===========================================================================================================================

void    dispatch_async_f(dispatch_queue_t inQueue, void* inContext, dispatch_function_t inFunction) {
    OSStatus            err;
    dispatch_item_t     item;
    Boolean             wasEmpty;

    DEBUG_USE_ONLY(err);

    require_action(DispatchQueueValid(inQueue), exit, err = EINVAL);

    item = (dispatch_item_t) calloc(1, sizeof(*item));
    require_action(item, exit, err = ENOMEM);

    item->function  = inFunction;
    item->context   = inContext;

    pthread_mutex_lock(inQueue->lockPtr);

    wasEmpty = (Boolean)(inQueue->itemsHead == NULL);
    if (wasEmpty) {
        dispatch_retain(inQueue);
    }

    *inQueue->itemsNext = item;
    inQueue->itemsNext = &item->next;

    if (inQueue == gDispatchMainQueue) {
#if( TARGET_OS_POSIX || TARGET_OS_THREADX )
        gDispatchMainQueue_WorkPending = true;
        pthread_cond_signal(gDispatchMainQueue_ConditionPtr);

#if( DISPATCH_LITE_CF_ENABLED )
        __LibDispatchCF_Schedule();
#endif
#elif( TARGET_OS_WINDOWS )
        if (!inQueue->pending) {
            BOOL        good;

            inQueue->pending = true;
            good = PostMessage(gDispatchMainQueueWindow, kLibDispatchWindowEvent_WorkPending, 0, 0);
            err = map_global_value_errno(good, good);
            check_noerr(err);
        }
#else
#error "update to support your platform"
#endif

        if (gDispatchMainQueueScheduleHookFunc) {
            gDispatchMainQueueScheduleHookFunc(NULL);
        }
    }
    else if (inQueue->concurrent) {
#if( TARGET_OS_WINDOWS )
        LONG        prev;

        prev = InterlockedIncrement(&gDispatchConcurrentCount);
        check(prev >= 0);
#endif

        err = __LibDispatch_ScheduleWork(__dispatch_queue_concurrent_drain, inQueue);
        check_noerr(err);
    }
    else if (wasEmpty && !inQueue->busy && (inQueue->suspendCount == 0)) {
#if( TARGET_OS_WINDOWS )
        LONG        prev;

        prev = InterlockedIncrement(&gDispatchSerialCount);
        check(prev >= 0);
#endif

        err = __LibDispatch_ScheduleWork(__dispatch_queue_serial_drain, inQueue);
        check_noerr(err);
    }

    pthread_mutex_unlock(inQueue->lockPtr);

exit:
    return;
}

//===========================================================================================================================
//  dispatch_sync
//===========================================================================================================================

typedef struct {
    dispatch_function_t     function;
    void*                   context;
    pthread_mutex_t         mutex;
    pthread_mutex_t*        mutexPtr;
    pthread_cond_t          condition;
    pthread_cond_t*         conditionPtr;
    Boolean                 done;

}   DispatchSyncItemData;

DEBUG_STATIC void   __dispatch_sync_callback(void* inContext);

void    dispatch_sync_f(dispatch_queue_t inQueue, void* inContext, dispatch_function_t inFunction) {
    int                         err;
    DispatchSyncItemData        itemData;

    itemData.function       = inFunction;
    itemData.context        = inContext;
    itemData.mutexPtr       = NULL;
    itemData.conditionPtr   = NULL;
    itemData.done           = false;

    require(DispatchQueueValid(inQueue), exit);
    check_string(inQueue != dispatch_get_current_queue(), "DEADLOCK: illegal from current queue");

    err = pthread_mutex_init(&itemData.mutex, NULL);
    require_noerr(err, exit);
    itemData.mutexPtr = &itemData.mutex;

    err = pthread_cond_init(&itemData.condition, NULL);
    require_noerr(err, exit);
    itemData.conditionPtr = &itemData.condition;

    dispatch_async_f(inQueue, &itemData, __dispatch_sync_callback);

    pthread_mutex_lock(itemData.mutexPtr);
    while (!itemData.done) {
        pthread_cond_wait(itemData.conditionPtr, itemData.mutexPtr);
    }
    pthread_mutex_unlock(itemData.mutexPtr);

exit:
    pthread_cond_forget(&itemData.conditionPtr);
    pthread_mutex_forget(&itemData.mutexPtr);
}

DEBUG_STATIC void   __dispatch_sync_callback(void* inContext) {
    DispatchSyncItemData* const        itemData = (DispatchSyncItemData*) inContext;

    itemData->function(itemData->context);

    pthread_mutex_lock(itemData->mutexPtr);
    itemData->done = true;
    pthread_cond_signal(itemData->conditionPtr);
    pthread_mutex_unlock(itemData->mutexPtr);
}

void    __dispatch_empty_callback(void* inContext) {
    (void) inContext; // Unused

    // Do nothing. This is only used to serialize via dispatch_sync_f().
}

//===========================================================================================================================
//  dispatch_get_global_queue
//===========================================================================================================================

dispatch_queue_t    dispatch_get_global_queue(long inPriority, unsigned long inFlags) {
    dispatch_queue_t        queue;
    OSStatus                err;

    (void) inFlags; // Unused

    queue = NULL;
    err = LibDispatch_EnsureInitialized();
    require_noerr(err, exit);

    if (inPriority == DISPATCH_QUEUE_PRIORITY_DEFAULT) {
        queue = gDispatchConcurrentQueues[ 1 ];
    }
    else if (inPriority >  DISPATCH_QUEUE_PRIORITY_DEFAULT) {
        queue = gDispatchConcurrentQueues[ 2 ];
    }
    else {
        queue = gDispatchConcurrentQueues[ 0 ];
    }
    require(queue, exit);

exit:
    return (queue);
}

//===========================================================================================================================
//  dispatch_get_current_queue
//===========================================================================================================================

dispatch_queue_t    dispatch_get_current_queue(void) {
    dispatch_queue_t        queue;
    OSStatus                err;

    queue = NULL;
    err = LibDispatch_EnsureInitialized();
    require_noerr(err, exit);

    queue = (dispatch_queue_t) pthread_getspecific(gDispatchKey_CurrentQueue);

exit:
    return (queue);
}

//===========================================================================================================================
//  dispatch_get_main_queue
//===========================================================================================================================

dispatch_queue_t    dispatch_get_main_queue(void) {
    dispatch_queue_t        queue;
    OSStatus                err;

    queue = NULL;
    err = LibDispatch_EnsureInitialized();
    require_noerr(err, exit);

    queue = gDispatchMainQueue;
    require(queue, exit);

exit:
    return (queue);
}

//===========================================================================================================================
//  dispatch_main
//===========================================================================================================================

#if( TARGET_OS_WINDOWS )
void    dispatch_main(void) {
    OSStatus                err;
    dispatch_queue_t        queue;
    BOOL                    result;
    MSG                     msg;

    err = LibDispatch_EnsureInitialized();
    require_noerr(err, exit);

    queue = gDispatchMainQueue;
    pthread_mutex_lock(queue->lockPtr);
    while (queue->base.refCount > 0) {
        queue->pending = false;
        __dispatch_queue_serial_drain_locked(queue);
        pthread_mutex_unlock(queue->lockPtr);

        result = GetMessage(&msg, gDispatchMainQueueWindow, 0, 0);
        check_string(result != 0, "should never get WM_QUIT here");
        err = map_global_value_errno(result != -1, result);
        require_noerr(err, exit);

        TranslateMessage(&msg);
        DispatchMessage(&msg);

        pthread_mutex_lock(queue->lockPtr);
    }

    gDispatchMainQueue = NULL;
    pthread_mutex_unlock(queue->lockPtr);
    __dispatch_queue_free(queue);

exit:
    return;
}
#else // !TARGET_OS_WINDOWS
void    dispatch_main(void) {
    OSStatus                err;
    dispatch_queue_t        queue;

    err = LibDispatch_EnsureInitialized();
    require_noerr(err, exit);

    queue = gDispatchMainQueue;
    pthread_mutex_lock(queue->lockPtr);
    while (queue->base.refCount > 0) {
        __dispatch_queue_serial_drain_locked(queue);

        while (!gDispatchMainQueue_WorkPending) {
            pthread_cond_wait(gDispatchMainQueue_ConditionPtr, queue->lockPtr);
        }
        gDispatchMainQueue_WorkPending = false;
    }

    gDispatchMainQueue = NULL;
    pthread_mutex_unlock(queue->lockPtr);
    __dispatch_queue_free(queue);

exit:
    return;
}
#endif // TARGET_OS_WINDOWS

//===========================================================================================================================
//  dispatch_main_drain_np
//===========================================================================================================================

void    dispatch_main_drain_np(void) {
    require(gDispatchMainQueue, exit);
    require(dispatch_get_current_queue() == gDispatchMainQueue, exit);

    __dispatch_queue_serial_drain(gDispatchMainQueue);

exit:
    return;
}

#if 0
#pragma mark -
#pragma mark == Queues ==
#endif

//===========================================================================================================================
//  dispatch_queue_create
//===========================================================================================================================

dispatch_queue_t    dispatch_queue_create(const char* inLabel, dispatch_queue_attr_t inAttr) {
    dispatch_queue_t        queue;
    OSStatus                err;

    (void) inAttr; // Unused

    queue = NULL;
    err = LibDispatch_EnsureInitialized();
    require_noerr(err, exit);

    queue = __dispatch_queue_create_internal(inLabel);

exit:
    return (queue);
}

//===========================================================================================================================
//  __dispatch_queue_create_internal
//===========================================================================================================================

DEBUG_STATIC dispatch_queue_t   __dispatch_queue_create_internal(const char* inLabel) {
    dispatch_queue_t        queue;
    OSStatus                err;
    dispatch_queue_t        obj;

    queue = NULL;
    obj = (dispatch_queue_t) calloc(1, sizeof(*obj));
    require(obj, exit);

    obj->base.magic     = kDispatchQueue_MagicGood;
    obj->base.refCount  = 1;
    obj->base.doFree    = __dispatch_queue_free;
    obj->priority       = DISPATCH_QUEUE_PRIORITY_DEFAULT;
    obj->itemsNext      = &obj->itemsHead;

    if (!inLabel) {
        inLabel = "";
    }
    strlcpy(obj->label, inLabel, sizeof(obj->label));

    err = pthread_mutex_init(&obj->lock, NULL);
    require_noerr(err, exit);
    obj->lockPtr = &obj->lock;

    queue = obj;
    obj = NULL;

exit:
    if (obj) {
        free(obj);
    }
    return (queue);
}

//===========================================================================================================================
//  __dispatch_queue_free
//===========================================================================================================================

DEBUG_STATIC void   __dispatch_queue_free(void* inArg) {
    dispatch_queue_t const      queue = (dispatch_queue_t) inArg;

    check(queue && (queue->base.magic == kDispatchQueue_MagicGood));
    check(queue->base.refCount == 0);
    check(queue->itemsHead == NULL);

    pthread_mutex_lock(queue->lockPtr);
    if (queue == gDispatchMainQueue) {
#if( TARGET_OS_WINDOWS )
        OSStatus        err;
        BOOL            good;

        good = PostMessage(gDispatchMainQueueWindow, kLibDispatchWindowEvent_WorkPending, 0, 0);
        err = map_global_value_errno(good, good);
        check_noerr(err);
#else
        gDispatchMainQueue_WorkPending = true;
        pthread_cond_signal(gDispatchMainQueue_ConditionPtr);
#endif

        pthread_mutex_unlock(queue->lockPtr);
    }
    else {
        pthread_mutex_unlock(queue->lockPtr);

        pthread_mutex_forget(&queue->lockPtr);
        queue->base.magic = kDispatchQueue_MagicBad;
        __dispatch_free_object(queue);
    }
}

//===========================================================================================================================
//  dispatch_queue_get_label
//===========================================================================================================================

const char*     dispatch_queue_get_label(dispatch_queue_t inQueue) {
    require(DispatchQueueValid(inQueue), exit);
    return (inQueue->label);

exit:
    return ("<<INVALID>>");
}

//===========================================================================================================================
//  __dispatch_queue_suspend
//===========================================================================================================================

DEBUG_STATIC void   __dispatch_queue_suspend(dispatch_queue_t inQueue) {
    require(DispatchQueueValid(inQueue), exit);
    require(inQueue != gDispatchMainQueue, exit);
    require(!inQueue->concurrent, exit);

    pthread_mutex_lock(inQueue->lockPtr);
    ++inQueue->suspendCount;
    check(inQueue->suspendCount >= 1);
    pthread_mutex_unlock(inQueue->lockPtr);

exit:
    return;
}

//===========================================================================================================================
//  __dispatch_queue_resume
//===========================================================================================================================

DEBUG_STATIC void   __dispatch_queue_resume(dispatch_queue_t inQueue) {
    OSStatus        err;

    DEBUG_USE_ONLY(err);

    require(DispatchQueueValid(inQueue), exit);
    require(inQueue != gDispatchMainQueue, exit);
    require(!inQueue->concurrent, exit);

    pthread_mutex_lock(inQueue->lockPtr);
    check(inQueue->suspendCount > 0);
    if ((--inQueue->suspendCount == 0) && inQueue->itemsHead) {
#if( TARGET_OS_WINDOWS )
        LONG        prev;

        prev = InterlockedIncrement(&gDispatchSerialCount);
        check(prev >= 0);
#endif

        err = __LibDispatch_ScheduleWork(__dispatch_queue_serial_drain, inQueue);
        check_noerr(err);
    }
    pthread_mutex_unlock(inQueue->lockPtr);

exit:
    return;
}

//===========================================================================================================================
//  __dispatch_queue_concurrent_drain
//===========================================================================================================================

DEBUG_STATIC void   __dispatch_queue_concurrent_drain(void* inContext) {
    dispatch_queue_t        lastQueue;
    dispatch_queue_t        queue;
    size_t                  i, n;
    Boolean                 releaseQueue;
    dispatch_item_t         item;

    (void) inContext; // Unused

    lastQueue = NULL;
    n = countof(gDispatchConcurrentQueues);
    for (i = n; i > 0;) {
        queue = gDispatchConcurrentQueues[ i - 1 ];
        check(DispatchQueueValid(queue));

        releaseQueue = false;
        pthread_mutex_lock(queue->lockPtr);
        if (((item = queue->itemsHead) != NULL) && ((queue->itemsHead = item->next) == NULL)) {
            queue->itemsNext = &queue->itemsHead;
            releaseQueue = true;
        }
        pthread_mutex_unlock(queue->lockPtr);

        if (item) {
            if (queue != lastQueue) {
                pthread_setspecific(gDispatchKey_CurrentQueue, queue);
                lastQueue = queue;
            }

            item->function(item->context);
            free(item);
            i = n; // Reset back to the highest priority queue so we always prefer it.
        }
        else {
            --i;
        }
        if (releaseQueue) {
            dispatch_release(queue);
        }
    }

#if( TARGET_OS_WINDOWS )
    InterlockedDecrement(&gDispatchConcurrentCount);
#endif
}

//===========================================================================================================================
//  __dispatch_queue_serial_drain
//===========================================================================================================================

DEBUG_STATIC void   __dispatch_queue_serial_drain(void* inContext) {
    dispatch_queue_t const      queue = (dispatch_queue_t) inContext;

    require(DispatchQueueValid(queue), exit2);

    pthread_mutex_lock(queue->lockPtr);
    dispatch_retain(queue);   // Retain so refCount doesn't drop to 0 with lock held.

    if (queue->busy) {
        goto exit;    // Exit if another thread is already draining the queue.
    }
    queue->busy = true;

    pthread_setspecific(gDispatchKey_CurrentQueue, queue);
    __dispatch_queue_serial_drain_locked(queue);

    queue->busy = false;

exit:
    pthread_mutex_unlock(queue->lockPtr);
    dispatch_release(queue);   // After lock is released so refCount doesn't drop to 0 with lock held.

exit2:
#if( TARGET_OS_WINDOWS )
    InterlockedDecrement(&gDispatchSerialCount);
#endif
    return;
}

//===========================================================================================================================
//  __dispatch_queue_serial_drain_locked
//
//  Note: Queue must be locked on entry, but this function may unlock and re-lock it before exiting.
//===========================================================================================================================

DEBUG_STATIC void   __dispatch_queue_serial_drain_locked(dispatch_queue_t inQueue) {
    dispatch_item_t     item;
    Boolean             releaseQueue;

    check_string((inQueue == gDispatchMainQueue) || (inQueue->base.refCount > 1), "caller didn't retain queue");
    check_string(dispatch_get_current_queue() == inQueue, "caller didn't set current queue");

    while ((item = inQueue->itemsHead) != NULL) {
        if (inQueue->suspendCount > 0) {
            break;
        }

        releaseQueue = false;
        if ((inQueue->itemsHead = item->next) == NULL) {
            inQueue->itemsNext = &inQueue->itemsHead;
            releaseQueue = true;
        }

        pthread_mutex_unlock(inQueue->lockPtr);
        item->function(item->context);
        free(item);
        if (releaseQueue) {
            dispatch_release(inQueue);
        }
        pthread_mutex_lock(inQueue->lockPtr);
    }
}

#if 0
#pragma mark -
#pragma mark == Sources ==
#endif

//===========================================================================================================================
//  dispatch_source_create
//===========================================================================================================================

dispatch_source_t
dispatch_source_create(
    dispatch_source_type_t  inType,
    uintptr_t               inHandle,
    unsigned long           inMask,
    dispatch_queue_t        inQueue) {
    dispatch_source_t       source;
    dispatch_source_t       obj;

    (void) inMask; // Unused

    source = NULL;
    obj = NULL;
    require(DispatchQueueValid(inQueue), exit);

    obj = (dispatch_source_t) calloc(1, sizeof(*obj));
    require(obj, exit);

    obj->base.magic         = kDispatchSource_MagicGood;
    obj->base.refCount      = 1;
    obj->base.doFree        = __LibDispatch_PlatformFreeSource;
    obj->queue              = inQueue;
    obj->suspendCount       = 1;
    obj->type               = inType;
    dispatch_retain(inQueue);

    if ((inType == DISPATCH_SOURCE_TYPE_READ) || (inType == DISPATCH_SOURCE_TYPE_WRITE)) {
        obj->u.rw.fd = (SocketRef) inHandle;

#if( TARGET_OS_WINDOWS )
        {
            OSStatus        err;

            err = __LibDispatch_AddSocket(obj->u.rw.fd, obj);
            require_noerr(err, exit);

            obj->u.rw.fdTracked = true;
        }
#endif
    }
    else if (inType == DISPATCH_SOURCE_TYPE_SIGNAL) {
        obj->u.sig.sig = (unsigned long) inHandle;
    }
    else if (inType == DISPATCH_SOURCE_TYPE_TIMER) {
        // "handle" and "mask" are unused for now.
    }
    else {
        dlogassert("bad type: %d", inType);
        goto exit;
    }

    source = obj;
    obj = NULL;

exit:
    if (obj) {
        __dispatch_source_free(obj);
    }
    return (source);
}

//===========================================================================================================================
//  __dispatch_source_free
//===========================================================================================================================

DEBUG_STATIC void   __dispatch_source_free(void* inContext) {
    dispatch_source_t const     source = (dispatch_source_t) inContext;

    check(source && (source->base.magic == kDispatchSource_MagicGood));
    check(source->base.refCount == 0);

#if( TARGET_OS_WINDOWS )
    if ((source->type == DISPATCH_SOURCE_TYPE_READ) || (source->type == DISPATCH_SOURCE_TYPE_WRITE)) {
        if (source->u.rw.fdTracked) {
            __LibDispatch_RemoveSocket(source->u.rw.fd);
            source->u.rw.fdTracked = false;
        }
    }
#endif

    if (!source->canceled && source->cancelFunction) {
        source->cancelFunction(source->base.context);
    }

    dispatch_release(source->queue);
    source->base.magic = kDispatchQueue_MagicBad;
    __dispatch_free_object(source);
}

//===========================================================================================================================
//  dispatch_source_set_event_handler
//===========================================================================================================================

void    dispatch_source_set_event_handler_f(dispatch_source_t inSource, dispatch_function_t inHandler) {
    inSource->handlerFunction = inHandler;
}

//===========================================================================================================================
//  dispatch_source_set_cancel_handler
//===========================================================================================================================

void    dispatch_source_set_cancel_handler_f(dispatch_source_t inSource, dispatch_function_t inHandler) {
    inSource->cancelFunction = inHandler;
}

//===========================================================================================================================
//  dispatch_source_cancel
//===========================================================================================================================

void    dispatch_source_cancel(dispatch_source_t inSource) {
    require(DispatchSourceValid(inSource), exit);

    pthread_mutex_lock(inSource->queue->lockPtr);

    if (inSource->canceled) {
        pthread_mutex_unlock(inSource->queue->lockPtr);
        return;
    }

    inSource->canceled = true;
    __LibDispatch_PlatformDisarmSourceAndUnlock(inSource);

    if (inSource->cancelFunction) {
        dispatch_async_f(inSource->queue, inSource->base.context, inSource->cancelFunction);
    }

exit:
    return;
}

//===========================================================================================================================
//  dispatch_source_set_timer
//===========================================================================================================================

void
dispatch_source_set_timer(
    dispatch_source_t   inSource,
    dispatch_time_t     inStart,
    uint64_t            inInterval,
    uint64_t            inLeeway) {
    (void) inLeeway; // Unused

    require(DispatchSourceValid(inSource), exit);

    pthread_mutex_lock(inSource->queue->lockPtr);

    inSource->u.timer.start         = inStart;
    inSource->u.timer.intervalMs    = inInterval / kNanosecondsPerMillisecond;
    if (inSource->u.timer.intervalMs == 0) {
        inSource->u.timer.intervalMs = 1;    // Round up to at least 1 millisecond.
    }

    if ((inSource->suspendCount == 0) && !inSource->canceled) {
        __LibDispatch_PlatformArmSourceAndUnlock(inSource);
    }
    else {
        pthread_mutex_unlock(inSource->queue->lockPtr);
    }

exit:
    return;
}

//===========================================================================================================================
//  __dispatch_source_suspend
//===========================================================================================================================

DEBUG_STATIC void   __dispatch_source_suspend(dispatch_source_t inSource) {
    require(DispatchSourceValid(inSource), exit);

    pthread_mutex_lock(inSource->queue->lockPtr);
    check(inSource->suspendCount >= 0);
    if (inSource->suspendCount++ == 0) {
        __LibDispatch_PlatformDisarmSourceAndUnlock(inSource);
    }
    else {
        pthread_mutex_unlock(inSource->queue->lockPtr);
    }

exit:
    return;
}

//===========================================================================================================================
//  __dispatch_source_resume
//===========================================================================================================================

DEBUG_STATIC void   __dispatch_source_resume(dispatch_source_t inSource) {
    require(DispatchSourceValid(inSource), exit);

    pthread_mutex_lock(inSource->queue->lockPtr);
    check(inSource->suspendCount > 0);
    if ((--inSource->suspendCount == 0) && !inSource->canceled) {
        __LibDispatch_PlatformArmSourceAndUnlock(inSource);
    }
    else {
        pthread_mutex_unlock(inSource->queue->lockPtr);
    }

exit:
    return;
}

//===========================================================================================================================
//  dispatch_source_get_data
//===========================================================================================================================

unsigned long   dispatch_source_get_data(dispatch_source_t inSource) {
    require(DispatchSourceValidOrFreeing(inSource), exit);

    if (inSource->type == DISPATCH_SOURCE_TYPE_READ) {
        return ((unsigned long) inSource->u.rw.avail);
    }
    else if (inSource->type == DISPATCH_SOURCE_TYPE_TIMER) {
        return (0);    // $$$ TO DO: fire count since last callback.
    }
    else {
        dlogassert("'%s' doesn't make sense for source type %d", __ROUTINE__, inSource->type);
    }

exit:
    return (0);
}

//===========================================================================================================================
//  dispatch_source_get_handle
//===========================================================================================================================

uintptr_t   dispatch_source_get_handle(dispatch_source_t inSource) {
    require(DispatchSourceValidOrFreeing(inSource), exit);

    if (inSource->type == DISPATCH_SOURCE_TYPE_READ) {
        return ((uintptr_t) inSource->u.rw.fd);
    }
    else if (inSource->type == DISPATCH_SOURCE_TYPE_WRITE) {
        return ((uintptr_t) inSource->u.rw.fd);
    }
    else if (inSource->type == DISPATCH_SOURCE_TYPE_SIGNAL) {
        return ((uintptr_t) inSource->u.sig.sig);
    }
    else {
        dlogassert("'%s' doesn't make sense for source %d", __ROUTINE__, inSource->type);
    }

exit:
    return (0);
}

#if 0
#pragma mark -
#pragma mark == Once ==
#endif

//===========================================================================================================================
//  dispatch_once_f_slow
//===========================================================================================================================

void    dispatch_once_f_slow(dispatch_once_t* inOnce, void* inContext, dispatch_function_t inFunction) {
    dispatch_once_t     prev;

    prev = atomic_val_compare_and_swap_32(inOnce, 0, 1);
    if (__builtin_expect(prev, 2) == 2) {
        // Already initialized. Nothing to do.
    }
    else if (prev == 0) {
        // Got lock. Initialize it and release the lock

        inFunction(inContext);
        atomic_read_write_barrier();
        *inOnce = 2;
    }
    else {
        // Another thread is initializing it. Yield while it completes.

        volatile atomic_once_t* const      volatileOnce = inOnce;

        do {
            atomic_yield();

        }
        while (*volatileOnce != 2);

        atomic_read_write_barrier();
    }
}

#if 0
#pragma mark -
#pragma mark == Semaphore ==
#endif

DEBUG_STATIC void   __dispatch_semaphore_free(void* inObj);

//===========================================================================================================================
//  dispatch_semaphore_create
//===========================================================================================================================

dispatch_semaphore_t    dispatch_semaphore_create(long inValue) {
    dispatch_semaphore_t        sem;
    dispatch_semaphore_t        obj;
    OSStatus                    err;

    sem = NULL;

    obj = (dispatch_semaphore_t) calloc(1, sizeof(*obj));
    require(obj, exit);
    obj->base.refCount  = 1;
    obj->base.doFree    = __dispatch_semaphore_free;
    obj->value          = inValue;

    err = pthread_mutex_init(&obj->mutex, NULL);
    require_noerr(err, exit);
    obj->mutexPtr = &obj->mutex;

    pthread_condattr_t condattr;
    pthread_condattr_init(&condattr);
    err = pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC);
    require_noerr(err, exit);

    err = pthread_cond_init(&obj->condition, &condattr);
    pthread_condattr_destroy(&condattr);
    require_noerr(err, exit);
    obj->conditionPtr = &obj->condition;

    sem = obj;
    obj = NULL;

exit:
    if (obj) {
        dispatch_release(obj);
    }
    return (sem);
}

//===========================================================================================================================
//  __dispatch_semaphore_free
//===========================================================================================================================

DEBUG_STATIC void   __dispatch_semaphore_free(void* inObj) {
    dispatch_semaphore_t const      obj = (dispatch_semaphore_t) inObj;

    pthread_mutex_forget(&obj->mutexPtr);
    pthread_cond_forget(&obj->conditionPtr);
    __dispatch_free_object(obj);
}

//===========================================================================================================================
//  dispatch_semaphore_wait
//===========================================================================================================================

long    dispatch_semaphore_wait(dispatch_semaphore_t inSem, dispatch_time_t inTimeout) {
    OSStatus        err;

    if (inTimeout == DISPATCH_TIME_FOREVER) {
        pthread_mutex_lock(inSem->mutexPtr);
        while (inSem->value <= 0) {
            err = pthread_cond_wait(inSem->conditionPtr, inSem->mutexPtr);
            check_noerr(err);
        }
        inSem->value -= 1;
        pthread_mutex_unlock(inSem->mutexPtr);
        err = kNoErr;
    }
    else {
#if( TARGET_OS_POSIX )
        dispatch_time_t     nowDT;
        struct timespec     deadline;

        if (((int64_t) inTimeout) < 0) {  // Negative if wall clock time.
            inTimeout   = (dispatch_time_t)(-((int64_t) inTimeout));
            nowDT       = (dispatch_time_t)(-((int64_t) dispatch_walltime(NULL, 0)));
        }
        else {
            nowDT = dispatch_time(DISPATCH_TIME_NOW, 0);
        }
        inTimeout = (nowDT < inTimeout) ? (inTimeout - nowDT) : 0;
        clock_gettime(CLOCK_MONOTONIC, &deadline);
        deadline.tv_sec += (inTimeout / 1000);
        deadline.tv_nsec += ((inTimeout % 1000) * kNanosecondsPerMillisecond);
        if (deadline.tv_nsec >= kNanosecondsPerSecond) {
            deadline.tv_sec  += 1;
            deadline.tv_nsec -= kNanosecondsPerSecond;
        }

        err = kNoErr;
        pthread_mutex_lock(inSem->mutexPtr);
        while (inSem->value <= 0) {
            err = pthread_cond_timedwait(inSem->conditionPtr, inSem->mutexPtr, &deadline);
            if (err) {
                break;
            }
        }
        if (!err) {
            inSem->value -= 1;
        }
        pthread_mutex_unlock(inSem->mutexPtr);
#else
        dlogassert("Timeouts not supported on this platform");
        err = kUnsupportedErr;
#endif
    }
    return (err);
}

//===========================================================================================================================
//  dispatch_semaphore_signal
//===========================================================================================================================

long    dispatch_semaphore_signal(dispatch_semaphore_t inSem) {
    OSStatus        err;

    DEBUG_USE_ONLY(err);

    pthread_mutex_lock(inSem->mutexPtr);
    inSem->value += 1;
    err = pthread_cond_signal(inSem->conditionPtr);
    check_noerr(err);
    pthread_mutex_unlock(inSem->mutexPtr);
    return (0);
}

#if 0
#pragma mark -
#pragma mark == Time ==
#endif

//===========================================================================================================================
//  dispatch_time
//===========================================================================================================================

dispatch_time_t dispatch_time(dispatch_time_t inWhen, int64_t inDelta) {
    if (inWhen == DISPATCH_TIME_FOREVER) {
        return (DISPATCH_TIME_FOREVER);
    }

    // Wall clock (negative).

    inDelta /= kNanosecondsPerMillisecond;
    if (((int64_t) inWhen) < 0) {
        if (inDelta >= 0) {
            if ((int64_t)(inWhen -= inDelta) >= 0) {
                return (DISPATCH_TIME_FOREVER);  // overflow
            }
            return (inWhen);
        }
        if ((int64_t)(inWhen -= inDelta) >= -1) {
            return ((dispatch_time_t) -2);  // underflow (use -2 because -1 == DISPATCH_TIME_FOREVER == forever)
        }
        return (inWhen);
    }

    // Default clock (milliseconds).

    if (inWhen == DISPATCH_TIME_NOW) {
        inWhen = __dispatch_milliseconds();
    }
    if (inDelta >= 0) {
        if ((int64_t)(inWhen += inDelta) <= 0) {
            return (DISPATCH_TIME_FOREVER);  // overflow
        }
        return (inWhen);
    }
    if ((int64_t)(inWhen += inDelta) < 1) {
        return (1);  // underflow
    }
    return (inWhen);
}

//===========================================================================================================================
//  dispatch_walltime
//===========================================================================================================================

dispatch_time_t dispatch_walltime(const struct timespec* ioWhen, int64_t inDelta) {
    int64_t     ms;

    if (ioWhen) {
        ms = (ioWhen->tv_sec * INT64_C_safe(kMillisecondsPerSecond)) + (ioWhen->tv_nsec / kNanosecondsPerMillisecond);
    }
    else {
        ms = __dispatch_wall_milliseconds();
    }

    inDelta /= kNanosecondsPerMillisecond;
    ms += inDelta;
    if (ms <= 1) {
        // Use -2 because -1 == DISPATCH_TIME_FOREVER == forever.

        return ((inDelta >= 0) ? DISPATCH_TIME_FOREVER : (uint64_t) INT64_C(-2));
    }
    return (-ms);
}

//===========================================================================================================================
//  __dispatch_milliseconds
//===========================================================================================================================

DEBUG_STATIC uint64_t   __dispatch_milliseconds(void) {
    return ((UpTicks() * kMillisecondsPerSecond) / UpTicksPerSecond());
}

//===========================================================================================================================
//  __dispatch_wall_milliseconds
//===========================================================================================================================

DEBUG_STATIC uint64_t   __dispatch_wall_milliseconds(void) {
#if( TARGET_OS_THREADX )
    return (time(NULL) * UINT64_C_safe(kMillisecondsPerSecond));      // $$$ TO DO: use something with more resolution.
#else
    struct timeval      tv;

    gettimeofday(&tv, NULL);
    return ((tv.tv_sec * UINT64_C_safe(kMillisecondsPerSecond)) + (tv.tv_usec / kMicrosecondsPerMillisecond));
#endif
}

#if 0
#pragma mark -
#pragma mark == CF Support ==
#endif

#if( DISPATCH_LITE_CF_ENABLED )

//===========================================================================================================================
//  __LibDispatchCF_EnsureInitialized
//
//  Note: Must be called with the initialize mutex locked.
//===========================================================================================================================

DEBUG_STATIC OSStatus   __LibDispatchCF_EnsureInitialized(void) {
    OSStatus                    err;
    CFRunLoopSourceContext      sourceContext = { 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };

    require_action_quiet(!gDispatchCFInitialized, exit, err = kNoErr);

    sourceContext.perform = __LibDispatchCF_SourcePerform;
    gDispatchCF_Source = CFRunLoopSourceCreate(NULL, 0, &sourceContext);
    require_action(gDispatchCF_Source, exit, err = kNoMemoryErr);

    gDispatchCF_MainRL = CFRunLoopGetMain();
    CFRunLoopAddSource(gDispatchCF_MainRL, gDispatchCF_Source, kCFRunLoopCommonModes);

    gDispatchCFInitialized = true;
    err = kNoErr;

exit:
    if (err) {
        __LibDispatchCF_Finalize();
    }
    return (err);
}

//===========================================================================================================================
//  __LibDispatchCF_Finalize
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatchCF_Finalize(void) {
    if (gDispatchCF_Source) {
        CFRunLoopSourceInvalidate(gDispatchCF_Source);
        CFRelease(gDispatchCF_Source);
        gDispatchCF_Source = NULL;
    }
    gDispatchCF_MainRL = NULL;
    gDispatchCFInitialized = false;
}

//===========================================================================================================================
//  __LibDispatchCF_Schedule
//===========================================================================================================================

DEBUG_STATIC OSStatus   __LibDispatchCF_Schedule(void) {
    CFRunLoopSourceSignal(gDispatchCF_Source);
    CFRunLoopWakeUp(gDispatchCF_MainRL);
    return (kNoErr);
}

//===========================================================================================================================
//  __LibDispatchCF_SourcePerform
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatchCF_SourcePerform(void* inContext) {
    (void) inContext; // Unused

    __dispatch_queue_serial_drain(gDispatchMainQueue);
}

#endif // DISPATCH_LITE_CF_ENABLED

#if 0
#pragma mark -
#pragma mark == KQueue Support ==
#endif

#if( DISPATCH_LITE_USE_KQUEUE )
//===========================================================================================================================
//  __LibDispatch_GetKQueue
//===========================================================================================================================

DEBUG_STATIC int    __LibDispatch_GetKQueue(void) {
    OSStatus            err;
    int                 pipeFDs[ 2 ];
    struct kevent       ke;
    int                 n;

    pthread_mutex_lock(gDispatchKQueue_MutexPtr);
    if (gDispatchKQueue_PipeSend < 0) {
        err = pipe(pipeFDs);
        err = map_global_noerr_errno(err);
        check_noerr(err);

        gDispatchKQueue_PipeSend = pipeFDs[ 1 ];
        gDispatchKQueue_PipeRecv = pipeFDs[ 0 ];
    }
    if (gDispatchKQueue_FD < 0) {
        gDispatchKQueue_FD = kqueue();
        err = map_fd_creation_errno(gDispatchKQueue_FD);
        check_noerr(err);

        EV_SET(&ke, gDispatchKQueue_PipeRecv, EVFILT_READ, EV_ADD, 0, 0, 0);
        n = kevent(gDispatchKQueue_FD, &ke, 1, NULL, 0, NULL);
        err = map_global_value_errno(n == 0, n);
        check_noerr(err);

        dispatch_async_f(gDispatchKQueue_DrainQueue, NULL, __LibDispatch_KQueueDrain);
    }
    pthread_mutex_unlock(gDispatchKQueue_MutexPtr);
    return (gDispatchKQueue_FD);
}

//===========================================================================================================================
//  __LibDispatch_PlatformFreeSource
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatch_PlatformFreeSourceCallBack(void* inContext);

DEBUG_STATIC void   __LibDispatch_PlatformFreeSource(void* inArg) {
    dispatch_source_t const     source = (dispatch_source_t) inArg;

    require(DispatchSourceValidOrFreeing(source), exit);

    // Mark it as canceled to prevent scheduling new work then schedule a callback on the kqueue thread to
    // serialize the delete behind any queued work.

    pthread_mutex_lock(source->queue->lockPtr);
    source->canceled = true;
    __LibDispatch_KQueueDispatchAsync(__LibDispatch_PlatformFreeSourceCallBack, source);
    pthread_mutex_unlock(source->queue->lockPtr);

exit:
    return;
}

DEBUG_STATIC void   __LibDispatch_PlatformFreeSourceCallBack(void* inContext) {
    dispatch_source_t const     source = (dispatch_source_t) inContext;

    check(source->base.refCount == 0);
    check(source->canceled);

    // Make sure the kqueue entry is disarmed so it won't fire again.

    pthread_mutex_lock(source->queue->lockPtr);
    __LibDispatch_PlatformDisarmSourceAndUnlock(source);

    // Serialize the final free on the source's queue to serialize it with any previous events that may be queued.

    dispatch_async_f(source->queue, source, __dispatch_source_free);
}

//===========================================================================================================================
//  __LibDispatch_PlatformArmSourceAndUnlock
//
//  Note: Owning queue must be locked on entry and it will be unlocked on exit.
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatch_PlatformArmSourceAndUnlock(dispatch_source_t inSource) {
    struct kevent       ke;
    int                 n;
    OSStatus            err;
    unsigned short      keFlags;
    uint64_t            milliseconds;

    if (inSource->type == DISPATCH_SOURCE_TYPE_READ) {
        EV_SET_compat(&ke, inSource->u.rw.fd, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, inSource);
    }
    else if (inSource->type == DISPATCH_SOURCE_TYPE_WRITE) {
        EV_SET_compat(&ke, inSource->u.rw.fd, EVFILT_WRITE, EV_ADD | EV_ONESHOT, 0, 0, inSource);
    }
    else if (inSource->type == DISPATCH_SOURCE_TYPE_SIGNAL) {
        keFlags = inSource->started ? EV_ENABLE : EV_ADD;
        EV_SET_compat(&ke, inSource->u.sig.sig, EVFILT_SIGNAL, keFlags, 0, 0, inSource);
    }
    else if (inSource->type == DISPATCH_SOURCE_TYPE_TIMER) {
        keFlags = inSource->started ? EV_ENABLE : EV_ADD;
        if (((int64_t) inSource->u.timer.start) < 0) {  // Wall clock time.
            uint64_t        tempStart;

            tempStart = -inSource->u.timer.start;
            milliseconds = tempStart - __dispatch_wall_milliseconds();
            if (milliseconds > tempStart) {
                milliseconds = 0;    // Start is in the past...force to now.
            }
        }
        else {
            milliseconds = inSource->u.timer.start - __dispatch_milliseconds();
            if (milliseconds > inSource->u.timer.start) {
                milliseconds = 0;    // Start is in the past...force to now.
            }
        }
        if (milliseconds <= 0) {
            milliseconds = 1;    // 0 confuses some kqueue implementations.
        }
        EV_SET_compat(&ke, (uintptr_t) inSource, EVFILT_TIMER, keFlags, 0, (intptr_t) milliseconds, inSource);
    }
    else {
        dlogassert("unknown source type: %d", inSource->type);
        goto exit;
    }
    inSource->started = true;

    n = kevent(__LibDispatch_GetKQueue(), &ke, 1, NULL, 0, NULL);
    err = map_global_value_errno(n == 0, n);
    require_noerr(err, exit);

exit:
    pthread_mutex_unlock(inSource->queue->lockPtr);
}

//===========================================================================================================================
//  __LibDispatch_PlatformDisarmSourceAndUnlock
//
//  Note: Owning queue must be locked on entry and it will be unlocked on exit.
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatch_PlatformDisarmSourceAndUnlock(dispatch_source_t inSource) {
    struct kevent       ke;
    int                 n;
    OSStatus            err;
    Boolean             deleting;

    if (!inSource->started) {
        goto exit;
    }

    if (inSource->type == DISPATCH_SOURCE_TYPE_READ) {
        EV_SET_compat(&ke, inSource->u.rw.fd, EVFILT_READ, EV_DELETE, 0, 0, inSource);
        deleting = true;
    }
    else if (inSource->type == DISPATCH_SOURCE_TYPE_WRITE) {
        EV_SET_compat(&ke, inSource->u.rw.fd, EVFILT_WRITE, EV_DELETE, 0, 0, inSource);
        deleting = true;
    }
    else if (inSource->type == DISPATCH_SOURCE_TYPE_SIGNAL) {
        deleting = inSource->canceled;
        EV_SET_compat(&ke, inSource->u.sig.sig, EVFILT_SIGNAL, deleting ? EV_DELETE : EV_DISABLE, 0, 0, inSource);
    }
    else if (inSource->type == DISPATCH_SOURCE_TYPE_TIMER) {
        deleting = inSource->canceled;
        EV_SET_compat(&ke, (uintptr_t) inSource, EVFILT_TIMER, deleting ? EV_DELETE : EV_DISABLE, 0, 0, inSource);
    }
    else {
        dlogassert("unknown source type: %d", inSource->type);
        goto exit;
    }

    n = kevent(__LibDispatch_GetKQueue(), &ke, 1, NULL, 0, NULL);
    err = map_global_value_errno(n == 0, n);
    if (err == ENOENT) {
        err = 0;
    }
    if (deleting) {
        inSource->started = false;
    }
    require_noerr(err, exit);

exit:
    pthread_mutex_unlock(inSource->queue->lockPtr);
}

//===========================================================================================================================
//  __LibDispatch_KQueueDispatchAsync
//===========================================================================================================================

DEBUG_STATIC OSStatus   __LibDispatch_KQueueDispatchAsync(dispatch_function_t inFunction, void* inContext) {
    OSStatus                    err;
    dispatch_simple_item        itemData;
    ssize_t                     n;

    itemData.function = inFunction;
    itemData.context  = inContext;

    // Note: pipe reads/writes <= PIPE_BUF are atomic.

    check(gDispatchKQueue_PipeSend >= 0);
    n = write(gDispatchKQueue_PipeSend, &itemData, sizeof(itemData));
    err = map_global_value_errno(n == (ssize_t) sizeof(itemData), n);
    require_noerr(err, exit);

exit:
    return (err);
}

//===========================================================================================================================
//  __LibDispatch_KQueueDrain
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatch_KQueueDrain(void* inContext) {
    struct kevent               ke;
    int                         kq;
    OSStatus                    err;
    dispatch_source_t           source;
    dispatch_simple_item        dispatchItemData;
    ssize_t                     n;

    (void) inContext; // Unused

    kq = __LibDispatch_GetKQueue();
    for (;;) {
        n = kevent(kq, NULL, 0, &ke, 1, NULL);
        err = map_global_value_errno(n > 0, n);
        if (err == EINTR) {
            continue;
        }
        require_noerr(err, exit);

        source = (dispatch_source_t) ke.udata;
        switch (ke.filter) {
            case EVFILT_READ:
                if (ke.ident == (uintptr_t) gDispatchKQueue_PipeRecv) {
                    // Note: pipe reads/writes <= PIPE_BUF are atomic.

                    n = read(gDispatchKQueue_PipeRecv, &dispatchItemData, sizeof(dispatchItemData));
                    err = map_global_value_errno(n == (ssize_t) sizeof(dispatchItemData), n);
                    check_noerr(err);
                    if (err) {
                        break;
                    }

                    if (dispatchItemData.function) {
                        dispatchItemData.function(dispatchItemData.context);
                        break;
                    }
                    else {
                        gcd_ulog(kLogLevelNotice, "*** quitting kqueue thread\n");
                        goto exit;
                    }
                }

                check(DispatchSourceValidOrFreeing(source));
                check(source->type == DISPATCH_SOURCE_TYPE_READ);

                source->u.rw.avail = (ke.data < 0) ? 0 : (size_t)(ke.data);
                dispatch_async_f(source->queue, source, __LibDispatch_KQueueFDEvent);
                break;

            case EVFILT_WRITE:
                check(DispatchSourceValidOrFreeing(source));
                check(source->type == DISPATCH_SOURCE_TYPE_WRITE);

                source->u.rw.avail = (ke.data < 0) ? 0 : (size_t)(ke.data);
                dispatch_async_f(source->queue, source, __LibDispatch_KQueueFDEvent);
                break;

            case EVFILT_SIGNAL:
                check(DispatchSourceValidOrFreeing(source));
                check(source->type == DISPATCH_SOURCE_TYPE_SIGNAL);

                dispatch_async_f(source->queue, source, __LibDispatch_KQueueSignalEvent);
                break;

            case EVFILT_TIMER:
                check(DispatchSourceValidOrFreeing(source));
                check(source->type == DISPATCH_SOURCE_TYPE_TIMER);

                if ((atomic_fetch_and_or_32(&source->pending, 1) & 1) == 0) {
                    dispatch_async_f(source->queue, source, __LibDispatch_KQueueTimerEvent);
                }
                break;

            default:
                dlogassert("unknown kevent filter: %d", ke.filter);
                break;
        }
    }

exit:
    return;
}

//===========================================================================================================================
//  __LibDispatch_KQueueFDEvent
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatch_KQueueFDEvent(void* inContext) {
    dispatch_source_t const     source = (dispatch_source_t) inContext;

    if (source->canceled || (source->suspendCount > 0)) {
        return;
    }

    source->handlerFunction(source->base.context);

    pthread_mutex_lock(source->queue->lockPtr);
    if (!source->canceled && (source->suspendCount == 0)) {
        __LibDispatch_PlatformArmSourceAndUnlock(source);
    }
    else {
        pthread_mutex_unlock(source->queue->lockPtr);
    }
}

//===========================================================================================================================
//  __LibDispatch_KQueueSignalEvent
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatch_KQueueSignalEvent(void* inContext) {
    dispatch_source_t const     source = (dispatch_source_t) inContext;

    if (source->canceled || (source->suspendCount > 0)) {
        return;
    }

    source->handlerFunction(source->base.context);
}

//===========================================================================================================================
//  __LibDispatch_KQueueTimerEvent
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatch_KQueueTimerEvent(void* inContext) {
    dispatch_source_t const     source = (dispatch_source_t) inContext;

    atomic_and_32(&source->pending, ~((int32_t) 1));
    if (source->canceled || (source->suspendCount > 0)) {
        return;
    }

    source->handlerFunction(source->base.context);
}
#endif // DISPATCH_LITE_USE_KQUEUE

#if 0
#pragma mark -
#pragma mark == Select Support ==
#endif

#if( DISPATCH_LITE_USE_SELECT )

//===========================================================================================================================
//  __LibDispatch_SelectEnsureInitialized
//===========================================================================================================================

DEBUG_STATIC OSStatus   __LibDispatch_SelectEnsureInitialized(void) {
    OSStatus        err;
    int             pipeFDs[ 2 ];

    gDispatchSelect_CommandQueue = __dispatch_queue_create_internal("com.apple.select-commands");
    require_action(gDispatchSelect_CommandQueue, exit, err = ENOMEM);

    err = pipe(pipeFDs);
    err = map_global_noerr_errno(err);
    require_noerr(err, exit);
    gDispatchSelect_CommandReadFD  = pipeFDs[ 0 ];
    gDispatchSelect_CommandWriteFD = pipeFDs[ 1 ];

    dispatch_async_f(gDispatchSelect_CommandQueue, NULL, __LibDispatch_SelectDrain);   // $$$ TO DO: do this lazily.

exit:
    return (err);
}

//===========================================================================================================================
//  __LibDispatch_SelectDrain
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatch_SelectDrain(void* inArg) {
    OSStatus                err;
    int                     n;
    dispatch_source_t       curr;
    dispatch_source_t*      next;
    uint64_t                nowTicks;
    uint64_t                deltaTicks;
    struct timeval          timeout;
    struct timeval*         timeoutPtr;
    fd_set*                 writeSetPtr;
    int                     maxFD;
    dispatch_source_t       expiredList;
    dispatch_source_t       expiredCurr;

    (void) inArg;

    pthread_setname_np_compat("gcd-select-drain");
    for (;;) {
        // Set up the timeout for the nearest timer (sorted by expiration time).

        curr = gDispatchSelect_TimerList;
        if (curr) {
            timeoutPtr = UpTicksToTimeValTimeout(curr->u.timer.expireTicks, &timeout);
        }
        else {
            timeoutPtr = NULL;
        }

        // Wait for an event.

        FD_ZERO(&gDispatchSelect_ReadSet);
        FD_ZERO(&gDispatchSelect_WriteSet);
        maxFD = gDispatchSelect_CommandReadFD;
        FD_SET(gDispatchSelect_CommandReadFD, &gDispatchSelect_ReadSet);
        writeSetPtr = NULL;
        for (curr = gDispatchSelect_ReadWriteList; curr; curr = curr->armedNext) {
            if (curr->type == DISPATCH_SOURCE_TYPE_READ) {
                if (!curr->canceled) {
                    check(IsValidFD(curr->u.rw.fd));
                    FD_SET(curr->u.rw.fd, &gDispatchSelect_ReadSet);
                    if (curr->u.rw.fd > maxFD) {
                        maxFD = curr->u.rw.fd;
                    }
                }
            }
            else if (curr->type == DISPATCH_SOURCE_TYPE_WRITE) {
                if (!curr->canceled) {
                    check(IsValidFD(curr->u.rw.fd));
                    FD_SET(curr->u.rw.fd, &gDispatchSelect_WriteSet);
                    if (curr->u.rw.fd > maxFD) {
                        maxFD = curr->u.rw.fd;
                    }
                    writeSetPtr = &gDispatchSelect_WriteSet;
                }
            }
        }
        n = select(maxFD + 1, &gDispatchSelect_ReadSet, writeSetPtr, NULL, timeoutPtr);
        err = select_errno(n);
        if (!err) {
            // Process ready file descriptors.

            if (FD_ISSET(gDispatchSelect_CommandReadFD, &gDispatchSelect_ReadSet)) {
                err = __LibDispatch_SelectHandleCommand(NULL);
                if (err) {
                    break;
                }
            }
            else {
                for (next = &gDispatchSelect_ReadWriteList; (curr = *next) != NULL;) {
                    check(DispatchSourceValidOrFreeing(curr));

                    if ((curr->type == DISPATCH_SOURCE_TYPE_READ) &&
                            FD_ISSET(curr->u.rw.fd, &gDispatchSelect_ReadSet)) {
                        *next = curr->armedNext;
                        dispatch_async_f(curr->queue, curr, __LibDispatch_SelectHandleReadWriteEvent);
                    }
                    else if ((curr->type == DISPATCH_SOURCE_TYPE_WRITE) &&
                             FD_ISSET(curr->u.rw.fd, &gDispatchSelect_WriteSet)) {
                        *next = curr->armedNext;
                        dispatch_async_f(curr->queue, curr, __LibDispatch_SelectHandleReadWriteEvent);
                    }
                    else {
                        next = &curr->armedNext;
                    }
                }
            }
        }
        else if (err != kTimeoutErr) {
            gcd_ulog(kLogLevelWarning, "### select() failed: %#m\n", err);
            sleep(1);
        }

        // Process expired timers.

        expiredList = NULL;
        nowTicks = UpTicks();
        while ((curr = gDispatchSelect_TimerList) != NULL) {
            if (nowTicks < curr->u.timer.expireTicks) {
                break;
            }
            gDispatchSelect_TimerList = curr->armedNext;
            curr->armedNext = expiredList;
            expiredList = curr;

            check(DispatchSourceValidOrFreeing(curr));
            check(curr->type == DISPATCH_SOURCE_TYPE_TIMER);

            if ((atomic_fetch_and_or_32(&curr->pending, 1) & 1) == 0) {
                curr->u.timer.count = 0;
                dispatch_async_f(curr->queue, curr, __LibDispatch_SelectHandleTimerEvent);
            }
            else {
                ++curr->u.timer.count;
            }
        }

        // Re-insert expired timers based on their new expiration.

        while ((expiredCurr = expiredList) != NULL) {
            expiredList = expiredCurr->armedNext;

            deltaTicks = MillisecondsToUpTicks(expiredCurr->u.timer.intervalMs);
            add_saturate(expiredCurr->u.timer.expireTicks, deltaTicks, UINT64_MAX);
            for (next = &gDispatchSelect_TimerList; (curr = *next) != NULL; next = &curr->armedNext) {
                if (expiredCurr->u.timer.expireTicks < curr->u.timer.expireTicks) {
                    break;
                }
            }
            expiredCurr->armedNext = *next;
            *next = expiredCurr;
        }
    }
    check(gDispatchSelect_ReadWriteList == NULL);
    check(gDispatchSelect_TimerList == NULL);
}

//===========================================================================================================================
//  __LibDispatch_SelectHandleCommand
//===========================================================================================================================

DEBUG_STATIC OSStatus   __LibDispatch_SelectHandleCommand(const dispatch_select_packet* inPkt) {
    OSStatus                    err;
    dispatch_select_packet      pkt;
    ssize_t                     n;
    dispatch_source_t*          next;
    dispatch_source_t           curr;

    if (inPkt == NULL) {
        n = read(gDispatchSelect_CommandReadFD, (char*) &pkt, sizeof(pkt));
        err = map_global_value_errno(n >= 0, n);
        require_noerr(err, exit);

        inPkt = &pkt;
    }
    switch (inPkt->cmd) {
        case kDispatchCommandArmSource:
            if (inPkt->source->type == DISPATCH_SOURCE_TYPE_TIMER) {
                uint64_t        milliseconds;

                if (((int64_t) inPkt->source->u.timer.start) < 0) {  // Wall clock time.
                    uint64_t        tempStart;

                    tempStart = -inPkt->source->u.timer.start;
                    milliseconds = tempStart - __dispatch_wall_milliseconds();
                    if (milliseconds > tempStart) {
                        milliseconds = 0;    // Start is in the past...force to now.
                    }
                }
                else {
                    milliseconds = inPkt->source->u.timer.start - __dispatch_milliseconds();
                    if (milliseconds > inPkt->source->u.timer.start) {
                        milliseconds = 0;    // Start is in the past...force to now.
                    }
                }
                inPkt->source->u.timer.expireTicks = UpTicks() + MillisecondsToUpTicks(milliseconds);

                // Remove the timer if it already exists and re-insert it based on the new expiration.

                for (next = &gDispatchSelect_TimerList; (curr = *next) != NULL; next = &curr->armedNext) {
                    if (curr == inPkt->source) {
                        *next = curr->armedNext;
                        break;
                    }
                }
                for (next = &gDispatchSelect_TimerList; (curr = *next) != NULL; next = &curr->armedNext) {
                    if (inPkt->source->u.timer.expireTicks < curr->u.timer.expireTicks) {
                        break;
                    }
                }
                inPkt->source->armedNext = *next;
                *next = inPkt->source;
            }
            else if ((inPkt->source->type == DISPATCH_SOURCE_TYPE_READ) ||
                     (inPkt->source->type == DISPATCH_SOURCE_TYPE_WRITE)) {
                for (next = &gDispatchSelect_ReadWriteList; (curr = *next) != NULL; next = &curr->armedNext) {
                    if (curr == inPkt->source) {
                        break;
                    }
                }
                if (!curr) {
                    inPkt->source->armedNext = NULL;
                    *next = inPkt->source;
                }
            }
            break;

        case kDispatchCommandDisarmSource:
            if (inPkt->source->type == DISPATCH_SOURCE_TYPE_TIMER) {
                for (next = &gDispatchSelect_TimerList; (curr = *next) != NULL; next = &curr->armedNext) {
                    if (curr == inPkt->source) {
                        *next = curr->armedNext;
                        break;
                    }
                }
            }
            else if ((inPkt->source->type == DISPATCH_SOURCE_TYPE_READ) ||
                     (inPkt->source->type == DISPATCH_SOURCE_TYPE_WRITE)) {
                for (next = &gDispatchSelect_ReadWriteList; (curr = *next) != NULL; next = &curr->armedNext) {
                    if (curr == inPkt->source) {
                        *next = curr->armedNext;
                        break;
                    }
                }
            }
            break;

        case kDispatchCommandFreeSource:
            check(inPkt->source->base.refCount == 0);
            check(inPkt->source->canceled);

            // Make sure the kqueue entry is disarmed so it won't fire again.

            pthread_mutex_lock(inPkt->source->queue->lockPtr);
            __LibDispatch_PlatformDisarmSourceAndUnlock(inPkt->source);

            // Serialize the final free on the source's queue to serialize it with any previous events that may be queued.

            dispatch_async_f(inPkt->source->queue, inPkt->source, __dispatch_source_free);
            break;

        case kDispatchCommandQuit:
            gcd_ulog(kLogLevelInfo, "quit command received...exiting\n");
            check(gDispatchSelect_QuitSem);
            if (gDispatchSelect_QuitSem) {
                dispatch_semaphore_signal(gDispatchSelect_QuitSem);
            }
            err = kEndingErr;
            goto exit;

        default:
            dlogassert("unknown command: %p", inPkt->cmd);
            err = kInternalErr;
            goto exit;
    }
    err = kNoErr;

exit:
    return (err);
}

//===========================================================================================================================
//  __LibDispatch_SelectHandleReadWriteEvent
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatch_SelectHandleReadWriteEvent(void* inContext) {
    dispatch_source_t const     source = (dispatch_source_t) inContext;

    if (source->canceled || (source->suspendCount > 0)) {
        return;
    }

    source->handlerFunction(source->base.context);

    pthread_mutex_lock(source->queue->lockPtr);
    if (!source->canceled && (source->suspendCount == 0)) {
        __LibDispatch_PlatformArmSourceAndUnlock(source);
    }
    else {
        pthread_mutex_unlock(source->queue->lockPtr);
    }
}

//===========================================================================================================================
//  __LibDispatch_SelectHandleTimerEvent
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatch_SelectHandleTimerEvent(void* inContext) {
    dispatch_source_t const     source = (dispatch_source_t) inContext;

    atomic_fetch_and_and_32(&source->pending, ~((int32_t) 1));
    if (source->canceled || (source->suspendCount > 0)) {
        return;
    }

    source->handlerFunction(source->base.context);
}

//===========================================================================================================================
//  __LibDispatch_PlatformFreeSource
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatch_PlatformFreeSource(void* inArg) {
    dispatch_source_t const     source = (dispatch_source_t) inArg;
    dispatch_select_packet      pkt;
    ssize_t                     n;
    OSStatus                    err;

    DEBUG_USE_ONLY(err);

    require(DispatchSourceValidOrFreeing(source), exit);

    // Mark it as canceled to prevent scheduling new work then schedule a callback on the kqueue thread to
    // serialize the delete behind any queued work.

    pthread_mutex_lock(source->queue->lockPtr);
    source->canceled = true;

    pkt.cmd     = kDispatchCommandFreeSource;
    pkt.source  = source;
    n = write(gDispatchSelect_CommandWriteFD, &pkt, sizeof(pkt));
    err = map_global_value_errno(n == (ssize_t) sizeof(pkt), n);
    check_noerr(err);
    pthread_mutex_unlock(source->queue->lockPtr);

exit:
    return;
}

//===========================================================================================================================
//  __LibDispatch_PlatformArmSourceAndUnlock
//
//  Note: Owning queue must be locked on entry and it will be unlocked on exit.
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatch_PlatformArmSourceAndUnlock(dispatch_source_t inSource) {
    __LibDispatch_PlatformArmOrDisarmSourceAndUnlock(inSource, kDispatchCommandArmSource);
}

//===========================================================================================================================
//  __LibDispatch_PlatformArmOrDisarmSourceAndUnlock
//
//  Note: Owning queue must be locked on entry and it will be unlocked on exit.
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatch_PlatformDisarmSourceAndUnlock(dispatch_source_t inSource) {
    __LibDispatch_PlatformArmOrDisarmSourceAndUnlock(inSource, kDispatchCommandDisarmSource);
}

//===========================================================================================================================
//  __LibDispatch_PlatformDisarmSourceAndUnlock
//
//  Note: Owning queue must be locked on entry and it will be unlocked on exit.
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatch_PlatformArmOrDisarmSourceAndUnlock(dispatch_source_t inSource, uint8_t inCmd) {
    dispatch_select_packet      pkt;
    ssize_t                     n;
    OSStatus                    err;

    DEBUG_USE_ONLY(err);

    pkt.cmd     = inCmd;
    pkt.source  = inSource;

    if (dispatch_get_current_queue() == gDispatchSelect_CommandQueue) {
        pthread_mutex_unlock(inSource->queue->lockPtr);
        __LibDispatch_SelectHandleCommand(&pkt);
    }
    else {
        n = write(gDispatchSelect_CommandWriteFD, &pkt, sizeof(pkt));
        err = map_global_value_errno(n == (ssize_t) sizeof(pkt), n);
        check_noerr(err);

        pthread_mutex_unlock(inSource->queue->lockPtr);
    }
}

#endif // DISPATCH_LITE_USE_SELECT

#if( TARGET_OS_WINDOWS )

#if 0
#pragma mark -
#pragma mark == Windows Support ==
#endif

//===========================================================================================================================
//  __LibDispatch_MainQueueWinProc
//===========================================================================================================================

DEBUG_STATIC LRESULT CALLBACK __LibDispatch_MainQueueWinProc(HWND inWindow, UINT inMsg, WPARAM inWParam,
                                                             LPARAM inLParam) {
    LRESULT     result;

    switch (inMsg) {
        case kLibDispatchWindowEvent_WorkPending:
            pthread_mutex_lock(gDispatchMainQueue->lockPtr);
            gDispatchMainQueue->pending = false;
            __dispatch_queue_serial_drain_locked(gDispatchMainQueue);
            pthread_mutex_unlock(gDispatchMainQueue->lockPtr);
            result = 0;
            break;

        default:
            result = DefWindowProc(inWindow, inMsg, inWParam, inLParam);
            break;
    }
    return (result);
}

//===========================================================================================================================
//  __LibDispatch_IOThreadStart
//===========================================================================================================================

typedef struct {
    pthread_mutex_t         mutex;
    pthread_mutex_t*        mutexPtr;
    pthread_cond_t          cond;
    pthread_cond_t*         condPtr;
    OSStatus                error;
    Boolean                 done;

}   LibDispatch_IOThreadStartData;

DEBUG_STATIC OSStatus   __LibDispatch_IOThreadStart(void) {
    OSStatus                            err;
    LibDispatch_IOThreadStartData       startData;

    // To send messages to a window on a specific thread, we have to create the window on that thread.
    // So we have to start the thread and make sure it is fully initialized before returning from here.

    startData.mutexPtr  = NULL;
    startData.condPtr   = NULL;
    startData.error     = kNoErr;
    startData.done      = false;

    err = pthread_mutex_init(&startData.mutex, NULL);
    require_noerr(err, exit);
    startData.mutexPtr = &startData.mutex;

    err = pthread_cond_init(&startData.cond, NULL);
    require_noerr(err, exit);
    startData.condPtr = &startData.cond;

    err = pthread_create(&gDispatchIOThread, NULL, __LibDispatch_IOThread, &startData);
    require_noerr(err, exit);
    gDispatchIOThreadPtr = &gDispatchIOThread;

    pthread_mutex_lock(startData.mutexPtr);
    while (!startData.done) {
        pthread_cond_wait(startData.condPtr, startData.mutexPtr);
    }
    err = startData.error;
    pthread_mutex_unlock(startData.mutexPtr);
    require_noerr(err, exit);

exit:
    pthread_mutex_forget(&startData.mutexPtr);
    pthread_cond_forget(&startData.condPtr);
    if (err) {
        __LibDispatch_IOThreadStop();
    }
    return (err);
}

//===========================================================================================================================
//  __LibDispatch_IOThreadStop
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatch_IOThreadStop(void) {
    BOOL            good;
    OSStatus        err;

    if (gDispatchIOThreadWindow) {
        good = PostMessage(gDispatchIOThreadWindow, WM_QUIT, 0, 0);
        err = map_global_value_errno(good, good);
        check_noerr(err);
    }
    if (gDispatchIOThreadPtr) {
        check(gDispatchIOThreadPtr);
        err = pthread_join(gDispatchIOThread, NULL);
        check_noerr(err);
        gDispatchIOThreadPtr = NULL;
    }
    check(gDispatchIOThreadWindow == NULL);
}

//===========================================================================================================================
//  __LibDispatch_IOThread
//===========================================================================================================================

DEBUG_STATIC void*  __LibDispatch_IOThread(void* inArg) {
    LibDispatch_IOThreadStartData* const       startData = (LibDispatch_IOThreadStartData*) inArg;
    OSStatus                                    err;
    Boolean                                     initialized;
    HINSTANCE                                   instance;
    WNDCLASSEX                                  wcex;
    HWND                                        wind;
    MSG                                         msg;
    BOOL                                        result;

    initialized = false;
    pthread_setname_np_compat("libdispatch_io");

    // Set up a window to process messages on this thread.

    instance = GetModuleHandle(NULL);
    err = map_global_value_errno(instance, instance);
    require_noerr(err, exit);

    wcex.cbSize         = sizeof(wcex);
    wcex.style          = 0;
    wcex.lpfnWndProc    = __LibDispatch_IOThreadWinProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = instance;
    wcex.hIcon          = NULL;
    wcex.hCursor        = NULL;
    wcex.hbrBackground  = NULL;
    wcex.lpszMenuName   = NULL;
    wcex.lpszClassName  = TEXT("libdispatch_io");
    wcex.hIconSm        = NULL;
    RegisterClassEx(&wcex);

    wind = CreateWindow(wcex.lpszClassName, wcex.lpszClassName, 0, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL,
                        instance, NULL);
    err = map_global_value_errno(wind, wind);
    require_noerr(err, exit);
    gDispatchIOThreadWindow = wind;

    PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);   // Force a message queue to be created.

    // Signal the start code that we've fully initialized.

    pthread_mutex_lock(startData->mutexPtr);
    startData->error = kNoErr;
    startData->done  = true;
    pthread_cond_signal(startData->condPtr);
    pthread_mutex_unlock(startData->mutexPtr);
    initialized = true;

    // Process messages until we receive WM_QUIT (i.e. GetMessage returns 0).

    for (;;) {
        result = GetMessage(&msg, gDispatchIOThreadWindow, 0, 0);
        if (result == 0) {
            break;
        }
        err = map_global_value_errno(result != -1, result);
        require_noerr(err, exit);

        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    result = DestroyWindow(gDispatchIOThreadWindow);
    err = map_global_value_errno(result, result);
    check_noerr(err);
    gDispatchIOThreadWindow = NULL;

exit:
    if (err && !initialized) {
        pthread_mutex_lock(startData->mutexPtr);
        startData->error = err;
        startData->done  = true;
        pthread_cond_signal(startData->condPtr);
        pthread_mutex_unlock(startData->mutexPtr);
    }
    return (NULL);
}

//===========================================================================================================================
//  __LibDispatch_IOThreadWinProc
//===========================================================================================================================

DEBUG_STATIC LRESULT CALLBACK __LibDispatch_IOThreadWinProc(HWND inWindow, UINT inMsg, WPARAM inWParam,
                                                            LPARAM inLParam) {
    LRESULT                 result;
    OSStatus                err;
    SOCKET                  sock;
    dispatch_source_t       source;
    DWORD                   event;

    switch (inMsg) {
        case kLibDispatchWindowEvent_Socket:
            sock  = (SOCKET) inWParam;
            err   = (OSStatus) WSAGETSELECTERROR(inLParam);
            event = WSAGETSELECTEVENT(inLParam);
            if (err) {
                gcd_ulog(kLogLevelNotice, "### socket %d error %#m, event 0x%X\n", sock, err, event);
            }

            err = __LibDispatch_LookupSocket(sock, NULL, &source);
            if (err == kNoErr) {
                dispatch_async_f(source->queue, source, __LibDispatch_WindowsSocketEvent);
            }
            result = 0;
            break;

        default:
            result = DefWindowProc(inWindow, inMsg, inWParam, inLParam);
            break;
    }
    return (result);
}

//===========================================================================================================================
//  __LibDispatch_LookupSocket
//===========================================================================================================================

DEBUG_STATIC OSStatus   __LibDispatch_LookupSocket(SOCKET inSock, dispatch_source_t inSource,
                                                   dispatch_source_t* outSource) {
    OSStatus                    err;
    DWORD                       hash;
    DispatchSocketHashRef*      next;
    DispatchSocketHashRef       curr;

    pthread_mutex_lock(gDispatchSocketHashTableMutexPtr);

    hash = (DWORD)(inSock % countof(gDispatchSocketHashTable));
    for (next = &gDispatchSocketHashTable[ hash ]; (curr = *next) != NULL; next = &curr->next) {
        if (curr->sock == inSock) {
            break;
        }
    }
    if (curr && outSource) {         // Lookup (found)
        *outSource = curr->source;
    }
    else if (curr && !inSource) { // Delete (found)
        gcd_ulog(kLogLevelChatty, "removing socket %d for source %p @ %N\n", inSock, curr->source);

        *next = curr->next;
        free(curr);
    }
    else if (curr) {                 // Duplicate?
        dlogassert("socket %d already there", inSock);
        err = kDuplicateErr;
        goto exit;
    }
    else if (inSource) {             // Add
        gcd_ulog(kLogLevelChatty, "adding socket %d for source %p @ %N\n", inSock, inSource);

        curr = (DispatchSocketHashRef) malloc(sizeof(*curr));
        require_action(curr, exit, err = ENOMEM);
        curr->next   = NULL;
        curr->sock   = inSock;
        curr->source = inSource;
        *next = curr;
    }
    else {
        gcd_ulog(kLogLevelNotice, "### socket %d msg when not in list (stale, queued msg?) @ %N\n", inSock);
        err = kNotFoundErr;
        goto exit;
    }
    err = kNoErr;

exit:
    pthread_mutex_unlock(gDispatchSocketHashTableMutexPtr);
    return (err);
}

//===========================================================================================================================
//  __LibDispatch_PlatformFreeSource
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatch_PlatformFreeSource(void* inArg) {
    dispatch_source_t const     source = (dispatch_source_t) inArg;

    require(DispatchSourceValidOrFreeing(source), exit);

    pthread_mutex_lock(source->queue->lockPtr);
    source->canceled = true;
    __LibDispatch_PlatformDisarmSourceAndUnlock(source);

    // Serialize the final free on the source's queue to serialize it with any previous events that may be queued.

    dispatch_async_f(source->queue, source, __dispatch_source_free);

exit:
    return;
}

//===========================================================================================================================
//  __LibDispatch_PlatformArmSourceAndUnlock
//
//  Note: Owning queue must be locked on entry and it will be unlocked on exit.
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatch_PlatformArmSourceAndUnlock(dispatch_source_t inSource) {
    OSStatus        err;

    if (inSource->type == DISPATCH_SOURCE_TYPE_READ) {
        err = WSAAsyncSelect(inSource->u.rw.fd, gDispatchIOThreadWindow, kLibDispatchWindowEvent_Socket,
                             FD_READ | FD_ACCEPT | FD_CONNECT | FD_CLOSE);
        err = map_global_value_errno(err != SOCKET_ERROR, err);
        require_noerr(err, exit);
    }
    else if (inSource->type == DISPATCH_SOURCE_TYPE_WRITE) {
        err = WSAAsyncSelect(inSource->u.rw.fd, gDispatchIOThreadWindow, kLibDispatchWindowEvent_Socket, FD_WRITE);
        err = map_global_value_errno(err != SOCKET_ERROR, err);
        require_noerr(err, exit);
    }
    else if (inSource->type == DISPATCH_SOURCE_TYPE_TIMER) {
        int64_t         signedStart;
        uint64_t        milliseconds;
        BOOL            good;

        signedStart = (int64_t) inSource->u.timer.start;
        if (signedStart < 0) { // Wall clock time.
            uint64_t        tempStart;

            tempStart = (uint64_t) -signedStart;
            milliseconds = tempStart - __dispatch_wall_milliseconds();
            if (milliseconds > tempStart) {
                milliseconds = 0;    // Start is in the past...force to now.
            }
        }
        else {
            milliseconds = inSource->u.timer.start - __dispatch_milliseconds();
            if (milliseconds > inSource->u.timer.start) {
                milliseconds = 0;    // Start is in the past...force to now.
            }
        }
        if (milliseconds <= 0) {
            milliseconds = 1;
        }

        check(inSource->u.timer.timer == NULL);
        good = CreateTimerQueueTimer(&inSource->u.timer.timer, NULL, __LibDispatch_WindowsTimerCallBack,
                                     inSource, (DWORD) milliseconds, (DWORD) inSource->u.timer.intervalMs, WT_EXECUTEDEFAULT);
        err = map_global_value_errno(good, good);
        require_noerr(err, exit);
    }
    else {
        dlogassert("unknown source type: %d", inSource->type);
        err = EINVAL;
        goto exit;
    }
    inSource->started = true;

exit:
    pthread_mutex_unlock(inSource->queue->lockPtr);
}

//===========================================================================================================================
//  __LibDispatch_PlatformDisarmSourceAndUnlock
//
//  Note: Owning queue must be locked on entry and it will be unlocked on exit.
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatch_PlatformDisarmSourceAndUnlock(dispatch_source_t inSource) {
    OSStatus        err;
    BOOL            good;
    Boolean         locked;
    HANDLE          completionEvent;
    DWORD           waitResult;

    locked = true;
    completionEvent = NULL;
    if (!inSource->started) {
        goto exit2;
    }

    if ((inSource->type == DISPATCH_SOURCE_TYPE_READ) || (inSource->type == DISPATCH_SOURCE_TYPE_WRITE)) {
        err = WSAAsyncSelect(inSource->u.rw.fd, gDispatchIOThreadWindow, kLibDispatchWindowEvent_Socket, 0);
        err = map_global_value_errno(err != SOCKET_ERROR, err);
        require_noerr(err, exit);

#if( TARGET_OS_WINDOWS )
        if (inSource->canceled && inSource->u.rw.fdTracked) {
            __LibDispatch_RemoveSocket(inSource->u.rw.fd);
            inSource->u.rw.fdTracked = false;
        }
#endif
    }
    else if (inSource->type == DISPATCH_SOURCE_TYPE_TIMER) {
        if (inSource->u.timer.timer) {
            completionEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
            err = map_global_value_errno(completionEvent, completionEvent);
            require_noerr(err, exit);

            good = DeleteTimerQueueTimer(NULL, inSource->u.timer.timer, completionEvent);
            err = map_global_value_errno(good, good);
            require_noerr(err, exit);
            inSource->u.timer.timer = NULL;

            pthread_mutex_unlock(inSource->queue->lockPtr);
            locked = false;

            waitResult = WaitForSingleObject(completionEvent, INFINITE);
            err = map_global_value_errno(waitResult == WAIT_OBJECT_0, waitResult);
            require_noerr(err, exit);
        }
    }
    else {
        dlogassert("unknown source type: %d", inSource->type);
        err = EINVAL;
        goto exit;
    }

exit:
    inSource->started = false;
exit2:
    if (locked) {
        pthread_mutex_unlock(inSource->queue->lockPtr);
    }
    if (completionEvent) {
        CloseHandle(completionEvent);
    }
}

//===========================================================================================================================
//  __LibDispatch_WindowsSocketEvent
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatch_WindowsSocketEvent(void* inContext) {
    dispatch_source_t const     source = (dispatch_source_t) inContext;

    if (source->canceled || (source->suspendCount > 0)) {
        return;
    }

    source->handlerFunction(source->base.context);

    pthread_mutex_lock(source->queue->lockPtr);
    if (!source->canceled && (source->suspendCount == 0)) {
        __LibDispatch_PlatformArmSourceAndUnlock(source);
    }
    else {
        pthread_mutex_unlock(source->queue->lockPtr);
    }
}

//===========================================================================================================================
//  __LibDispatch_WindowsTimerCallBack
//===========================================================================================================================

DEBUG_STATIC void CALLBACK  __LibDispatch_WindowsTimerCallBack(void* inArg, BOOLEAN inFired) {
    dispatch_source_t const     source = (dispatch_source_t) inArg;

    (void) inFired; // Unused

    if ((atomic_fetch_and_or_32(&source->pending, 1) & 1) == 0) {
        dispatch_async_f(source->queue, source, __LibDispatch_WindowsTimerEvent);
    }
}

//===========================================================================================================================
//  __LibDispatch_WindowsTimerEvent
//===========================================================================================================================

DEBUG_STATIC void   __LibDispatch_WindowsTimerEvent(void* inContext) {
    dispatch_source_t const     source = (dispatch_source_t) inContext;

    atomic_fetch_and_and_32(&source->pending, ~((int32_t) 1));
    if (source->canceled || (source->suspendCount > 0)) {
        return;
    }

    source->handlerFunction(source->base.context);
}
#endif // TARGET_OS_WINDOWS

#if 0
#pragma mark -
#pragma mark == Debugging ==
#endif

#if( !EXCLUDE_UNIT_TESTS )
//===========================================================================================================================
//  DispatchLite_Test
//===========================================================================================================================

void    DispatchLite_Test1(void* inContext);
void    DispatchLite_Test2(void* inContext);
void    DispatchLite_OnceTest(void* inContext);
void    DispatchLite_TestQueueFinalizerCallBack(void* inContext);
void    DispatchLite_CancelCallBack(void* inContext);
#if( TARGET_OS_POSIX )
void    DispatchLite_ReadTestCallBack(void* inContext);
void    DispatchLite_WriteTestCallBack(void* inContext);
#endif
void    DispatchLite_TimerTestCallBack(void* inContext);
void    DispatchLite_TimerTest2CallBack(void* inContext);
void    DispatchLite_AfterCallBack(void* inContext);
#if( DISPATCH_LITE_CF_ENABLED )
void    DispatchLite_TestCF(void* inContext);
#endif
#if( TARGET_OS_WINDOWS )
void    DispatchLite_TestWindowsMessageLoop(void* inContext);
#endif

void    DispatchLiteTest_WaitUntilDone(void);
void    DispatchLiteTest_WaitUntilSourceDone(void);

dispatch_queue_t        gDispatchLiteTestQueue  = NULL;
volatile int32_t        gDispatchLiteTest1      = 0;
volatile int32_t        gDispatchLiteTest2      = 0;
volatile Boolean        gDispatchLiteTestDone   = false;
volatile OSStatus       gDispatchLiteTestErr    = kNoErr;
volatile Boolean        gDispatchLiteSourceDone = false;

typedef struct {
    dispatch_source_t       source;
    void*                   context;

}   SourceTuple;

OSStatus    DispatchLite_Test(void) {
    OSStatus                err;
    dispatch_queue_t        dq;
    dispatch_semaphore_t    sem;
#if( TARGET_OS_POSIX )
    int                     fd;
#endif
    dispatch_source_t       source;
    SourceTuple             sourceTuple;
    int                     n;
    dispatch_once_t         once;
    struct timespec         ts;
    dispatch_time_t         dt1, dt2;
    int64_t                 delta;
    uint64_t                u64;

    gDispatchLiteTestQueue  = NULL;
    gDispatchLiteTest1      = 0;
    gDispatchLiteTest2      = 0;
    gDispatchLiteTestDone   = false;
    gDispatchLiteTestErr    = kNoErr;
    gDispatchLiteSourceDone = false;

    // Serial Test

    gcd_ulog(kLogLevelMax, "\n");
    gcd_ulog(kLogLevelMax, "== %s: serial test\n", __ROUTINE__);

    dq = dispatch_queue_create("SerialTest", NULL);
    require_action(dq, exit, err = -1);
    dispatch_set_finalizer_f(dq, DispatchLite_TestQueueFinalizerCallBack);
    gDispatchLiteTestQueue = dq;

    dispatch_async_f(dq, (void*)(intptr_t)   5, DispatchLite_Test1);
    dispatch_async_f(dq, (void*)(intptr_t)  50, DispatchLite_Test1);
    dispatch_async_f(dq, (void*)(intptr_t) 500, DispatchLite_Test1);

    dispatch_sync_f(dq, (void*)(intptr_t) 5000, DispatchLite_Test1);
    require_action(gDispatchLiteTest1 == 5555, exit, err = kResponseErr);
    require_action(!gDispatchLiteTestDone, exit, err = -1);

    dispatch_release(dq);
    DispatchLiteTest_WaitUntilDone();

    // Concurrent Test

    gcd_ulog(kLogLevelMax, "\n");
    gcd_ulog(kLogLevelMax, "== %s: concurrent test\n", __ROUTINE__);

    dq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0);
    dispatch_async_f(dq, (void*)(intptr_t) 5, DispatchLite_Test2);

    dq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async_f(dq, (void*)(intptr_t) 50, DispatchLite_Test2);

    dq = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
    dispatch_async_f(dq, (void*)(intptr_t)  500, DispatchLite_Test2);
    dispatch_async_f(dq, (void*)(intptr_t) 5000, DispatchLite_Test2);

    DispatchLiteTest_WaitUntilDone();
    require_action(gDispatchLiteTest2 == 5555, exit, err = kResponseErr);

    // Once Test

    gcd_ulog(kLogLevelMax, "\n");
    gcd_ulog(kLogLevelMax, "== %s: once test\n", __ROUTINE__);

    n = 0;
    once = 0;
    dispatch_once_f(&once, &n, DispatchLite_OnceTest);
    require_action(n == 1, exit, err = -1);
    dispatch_once_f(&once, &n, DispatchLite_OnceTest);
    require_action(n == 1, exit, err = -1);
    dispatch_once_f(&once, &n, DispatchLite_OnceTest);
    require_action(n == 1, exit, err = -1);

    // Semaphore Test

    gcd_ulog(kLogLevelMax, "\n");
    gcd_ulog(kLogLevelMax, "== %s: semaphore test\n", __ROUTINE__);

    sem = dispatch_semaphore_create(0);
    require_action(sem, exit, err = -1);

    dispatch_semaphore_signal(sem);
    dispatch_semaphore_signal(sem);
    err = (OSStatus) dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    require_noerr(err, exit);
    err = (OSStatus) dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
    require_noerr(err, exit);

    dispatch_release(sem);

    // Time Test

#if( TARGET_OS_WINDOWS )
    ts.tv_sec = (long) time(NULL);
#else
    ts.tv_sec = time(NULL);
#endif
    ts.tv_nsec = 0;
    dt1 = dispatch_walltime(&ts, 0);
    dt2 = dispatch_walltime(NULL, 0);
    delta = (int64_t)(dt1 - dt2);
    if (delta < 0) {
        delta = -delta;
    }
    require_action(delta <= 2000000000, exit, err = kResponseErr);

    // Timer Test

    gcd_ulog(kLogLevelMax, "\n");
    gcd_ulog(kLogLevelMax, "== %s: timer test\n", __ROUTINE__);

    dq = dispatch_queue_create("TimerTest", NULL);
    require_action(dq, exit, err = -1);
    gDispatchLiteTestQueue = dq;

    n = 0;
    source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dq);
    require_action(source, exit, err = -1);
    sourceTuple.source = source;
    sourceTuple.context = &n;
    dispatch_set_context(source, &sourceTuple);
    dispatch_source_set_event_handler_f(source, DispatchLite_TimerTestCallBack);
    dispatch_source_set_cancel_handler_f(source, DispatchLite_CancelCallBack);
    dispatch_source_set_timer(source, dispatch_time(DISPATCH_TIME_NOW, 200 * kNanosecondsPerMillisecond),
                              200 * kNanosecondsPerMillisecond, kNanosecondsPerMillisecond);
    dispatch_resume(source);

    DispatchLiteTest_WaitUntilDone();
    require_action(n == 3, exit, err = -1);

    dispatch_release(source);
    DispatchLiteTest_WaitUntilSourceDone();

    // Timer Test 2

    gcd_ulog(kLogLevelMax, "\n");
    gcd_ulog(kLogLevelMax, "== %s: timer test 2\n", __ROUTINE__);

    n = 0;
    source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dq);
    require_action(source, exit, err = -1);
    sourceTuple.source = source;
    sourceTuple.context = &n;
    dispatch_set_context(source, &sourceTuple);
    dispatch_source_set_event_handler_f(source, DispatchLite_TimerTest2CallBack);
    dispatch_source_set_cancel_handler_f(source, DispatchLite_CancelCallBack);
    dispatch_source_set_timer(source, dispatch_time(DISPATCH_TIME_NOW, 1000 * kNanosecondsPerMillisecond),
                              DISPATCH_TIME_FOREVER, 0);
    dispatch_resume(source);

    u64 = UpTicks();
    DispatchLiteTest_WaitUntilDone();
    u64 = UpTicksToMilliseconds(UpTicks() - u64);
    require_action(n == 3, exit, err = kResponseErr);
    require_action((u64 >= 2950) && (u64 <= 3200), exit, err = kRangeErr);

    dispatch_release(source);
    DispatchLiteTest_WaitUntilSourceDone();

    // dispatch_after

    gcd_ulog(kLogLevelMax, "\n");
    gcd_ulog(kLogLevelMax, "== %s: dispatch_after test\n", __ROUTINE__);

    n = 0;
    sourceTuple.source = NULL;
    sourceTuple.context = &n;
    u64 = UpTicks();
    dispatch_after_f(dispatch_time(DISPATCH_TIME_NOW, 100 * kNanosecondsPerMillisecond), dq, &sourceTuple,
                     DispatchLite_AfterCallBack);
    DispatchLiteTest_WaitUntilDone();
    u64 = UpTicksToMilliseconds(UpTicks() - u64);
    require_action(n == 1, exit, err = -1);
    require_action((u64 >= 90) && (u64 <= 200), exit, err = kRangeErr);

    // Write Test

#if( TARGET_OS_POSIX )
    gcd_ulog(kLogLevelMax, "\n");
    gcd_ulog(kLogLevelMax, "== %s: write test\n", __ROUTINE__);

    dq = dispatch_queue_create("WriteTest", NULL);
    require_action(dq, exit, err = -1);
    gDispatchLiteTestQueue = dq;

    fd = open("/tmp/DispatchLiteReadWriteTest", O_CREAT | O_RDWR, S_IRWXU);
    err = map_fd_creation_errno(fd);
    require_noerr(err, exit);

    source = dispatch_source_create(DISPATCH_SOURCE_TYPE_WRITE, fd, 0, dq);
    require_action(source, exit, err = -1);
    dispatch_set_context(source, source);
    dispatch_source_set_event_handler_f(source, DispatchLite_WriteTestCallBack);
    dispatch_source_set_cancel_handler_f(source, DispatchLite_CancelCallBack);
    dispatch_resume(source);

    DispatchLiteTest_WaitUntilDone();
    require_noerr(gDispatchLiteTestErr, exit);

    dispatch_release(source);
    DispatchLiteTest_WaitUntilSourceDone();
    err = close(fd);
    err = map_global_noerr_errno(err);
    require_noerr(err, exit);

    // Read Test

    gcd_ulog(kLogLevelMax, "\n");
    gcd_ulog(kLogLevelMax, "== %s: read test\n", __ROUTINE__);

    fd = open("/tmp/DispatchLiteReadWriteTest", O_RDONLY, 0);
    err = map_fd_creation_errno(fd);
    require_noerr(err, exit);

    source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ, fd, 0, dq);
    require_action(source, exit, err = -1);
    dispatch_set_context(source, source);
    dispatch_source_set_event_handler_f(source, DispatchLite_ReadTestCallBack);
    dispatch_source_set_cancel_handler_f(source, DispatchLite_CancelCallBack);
    dispatch_resume(source);

    DispatchLiteTest_WaitUntilDone();
    require_noerr(gDispatchLiteTestErr, exit);

    dispatch_release(source);
    DispatchLiteTest_WaitUntilSourceDone();
    err = close(fd);
    err = map_global_noerr_errno(err);
    require_noerr(err, exit);
    unlink("/tmp/DispatchLiteReadWriteTest");

    dispatch_release(dq);
#else
    gcd_ulog(kLogLevelMax, "### writes not implemented so read/write test skipped\n");
#endif

    // Main Queue Test

    usleep(100000);   // 100ms delay so logging doesn't intersperse.
    gcd_ulog(kLogLevelMax, "\n");
    gcd_ulog(kLogLevelMax, "== %s: main queue test\n", __ROUTINE__);

    dq = dispatch_get_main_queue();
    gDispatchLiteTestQueue = dq;

    n = 0;
    source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dq);
    require_action(source, exit, err = -1);
    sourceTuple.source = source;
    sourceTuple.context = &n;
    dispatch_set_context(source, &sourceTuple);
    dispatch_source_set_event_handler_f(source, DispatchLite_TimerTestCallBack);
    dispatch_source_set_cancel_handler_f(source, DispatchLite_CancelCallBack);
    dispatch_source_set_timer(source, dispatch_time(DISPATCH_TIME_NOW, 200 * kNanosecondsPerMillisecond),
                              200 * kNanosecondsPerMillisecond, kNanosecondsPerMillisecond);
    dispatch_resume(source);

    dispatch_main();
    require_action(n == 3, exit, err = -1);

    LibDispatch_Finalize();

    // CF Test

#if( DISPATCH_LITE_CF_ENABLED )
    gcd_ulog(kLogLevelMax, "\n");
    gcd_ulog(kLogLevelMax, "== %s: CF test\n", __ROUTINE__);

    dq = dispatch_get_main_queue();
    gDispatchLiteTestQueue = dq;

    gDispatchLiteTest1 = 0;
    dispatch_async_f(dq, (void*)(intptr_t) 1234, DispatchLite_TestCF);
    dispatch_async_f(dq, (void*)(intptr_t) 2345, DispatchLite_TestCF);

    CFRunLoopRun();
    require_action(gDispatchLiteTest1 == 3579, exit, err = -1);
#endif

    // Windows Message Loop Test

#if( TARGET_OS_WINDOWS )
    gcd_ulog(kLogLevelMax, "\n");
    gcd_ulog(kLogLevelMax, "== %s: Windows message loop test\n", __ROUTINE__);

    gDispatchLiteTestDone = false;

    dq = dispatch_get_main_queue();
    gDispatchLiteTestQueue = dq;

    gDispatchLiteTest1 = 0;
    dispatch_async_f(dq, (void*)(intptr_t) 1234, DispatchLite_TestWindowsMessageLoop);
    dispatch_async_f(dq, (void*)(intptr_t) 2345, DispatchLite_TestWindowsMessageLoop);

    while (!gDispatchLiteTestDone) {
        BOOL        result;
        MSG         msg;

        result = GetMessage(&msg, NULL, 0, 0);
        check_string(result != 0, "should never get WM_QUIT here");
        err = map_global_value_errno(result != -1, result);
        require_noerr(err, exit);

        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    require_action(gDispatchLiteTest1 == 3579, exit, err = -1);
#endif

exit:
    printf("DispatchLite_Test: %s\n", !err ? "PASSED" : "FAILED");
    return (err);
}

void    DispatchLite_Test1(void* inContext) {
    int     x;

    require(dispatch_get_current_queue() == gDispatchLiteTestQueue, exit);

    x = (int)(intptr_t) inContext;
    gcd_ulog(kLogLevelMax, "\t%s: pthread = %p, x = %5d, gDispatchLiteTest1 = %5d\n",
             __ROUTINE__, (uintptr_t) pthread_self(), x, gDispatchLiteTest1);
    if ((x ==    5) && (gDispatchLiteTest1 ==   0)) {
        gDispatchLiteTest1 += x;
    }
    else if ((x ==   50) && (gDispatchLiteTest1 ==   5)) {
        gDispatchLiteTest1 += x;
    }
    else if ((x ==  500) && (gDispatchLiteTest1 ==  55)) {
        gDispatchLiteTest1 += x;
    }
    else if ((x == 5000) && (gDispatchLiteTest1 == 555)) {
        gDispatchLiteTest1 += x;
    }
    else {
        dlogassert("bad dispatch: x = %d, gDispatchLiteTest1 = %d", x, gDispatchLiteTest1);
    }

exit:
    return;
}

void    DispatchLite_Test2(void* inContext) {
    int32_t     x;

    x = (int32_t)(intptr_t) inContext;
    if (x ==   5) {
        require(dispatch_get_current_queue() == dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), exit);
    }
    else if (x ==  50) {
        require(dispatch_get_current_queue() == dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), exit);
    }
    else if (x == 500) {
        require(dispatch_get_current_queue() == dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), exit);
    }
    else {
        require(dispatch_get_current_queue() == dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), exit);
    }

    usleep(10000);

    gcd_ulog(kLogLevelMax, "\t%s: pthread = %p, x = %5d\n", __ROUTINE__, (uintptr_t) pthread_self(), x);
    x = atomic_add_and_fetch_32((int32_t*) &gDispatchLiteTest2, x);
    if (x == 5555) {
        gDispatchLiteTestDone = true;
    }

exit:
    return;
}

void    DispatchLite_OnceTest(void* inContext) {
    *((int*) inContext) += 1;
}

void    DispatchLite_TestQueueFinalizerCallBack(void* inContext) {
    (void) inContext;

    gDispatchLiteTestDone = true;
}

void    DispatchLite_CancelCallBack(void* inContext) {
    (void) inContext; // Unused

    gDispatchLiteSourceDone = true;
}

#if( TARGET_OS_POSIX )
void    DispatchLite_ReadTestCallBack(void* inContext) {
    dispatch_source_t const     source = (dispatch_source_t) inContext;
    OSStatus                    err;
    int                         fd;
    char                        buf[ 4 ];
    ssize_t                     n;

    require_action(dispatch_get_current_queue() == gDispatchLiteTestQueue, exit, err = -1);
#if( !DISPATCH_LITE_USE_SELECT )
    require_action(dispatch_source_get_data(source) == 4, exit, err = -1);
#endif

    fd = (int) dispatch_source_get_handle(source);
    n = read(fd, buf, 4);
    err = map_global_value_errno(n == 4, n);
    require_noerr(err, exit);

    gcd_ulog(kLogLevelNotice, "\t%s: err = %#m\n", __ROUTINE__, err);
    dispatch_source_cancel(source);
    gDispatchLiteTestDone = true;

exit:
    gDispatchLiteTestErr = err;
}

void    DispatchLite_WriteTestCallBack(void* inContext) {
    dispatch_source_t const     source = (dispatch_source_t) inContext;
    OSStatus                    err;
    int                         fd;
    ssize_t                     n;

    require_action(dispatch_get_current_queue() == gDispatchLiteTestQueue, exit, err = -1);

    fd = (int) dispatch_source_get_handle(source);
    n = write(fd, "test", 4);
    err = map_global_value_errno(n == 4, n);
    require_noerr(err, exit);

    gcd_ulog(kLogLevelNotice, "\t%s: err = %#m\n", __ROUTINE__, err);
    dispatch_source_cancel(source);
    gDispatchLiteTestDone = true;

exit:
    gDispatchLiteTestErr = err;
}
#endif // TARGET_OS_POSIX

void    DispatchLite_TimerTestCallBack(void* inContext) {
    SourceTuple* const         context = (SourceTuple*) inContext;
    int* const                 n = (int*)(context->context);

    require_action(dispatch_get_current_queue() == gDispatchLiteTestQueue, exit, gDispatchLiteTestErr = -1);

    *n += 1;
    gcd_ulog(kLogLevelNotice, "\t%s: n = %d\n", __ROUTINE__, *n);
    if (*n == 3) {
        dispatch_source_cancel(context->source);
        if (dispatch_get_current_queue() == dispatch_get_main_queue()) {
            dispatch_release(context->source);
            dispatch_release(dispatch_get_main_queue());
        }
        gDispatchLiteTestDone = true;
    }

exit:
    return;
}

void    DispatchLite_TimerTest2CallBack(void* inContext) {
    SourceTuple* const         context = (SourceTuple*) inContext;
    int* const                 n = (int*)(context->context);

    require_action(dispatch_get_current_queue() == gDispatchLiteTestQueue, exit, gDispatchLiteTestErr = -1);

    *n += 1;
    gcd_ulog(kLogLevelNotice, "\t%s: n = %d\n", __ROUTINE__, *n);
    if (*n == 3) {
        dispatch_source_cancel(context->source);
        if (dispatch_get_current_queue() == dispatch_get_main_queue()) {
            dispatch_release(context->source);
            dispatch_release(dispatch_get_main_queue());
        }
        gDispatchLiteTestDone = true;
    }
    else {
        dispatch_source_set_timer(context->source, dispatch_time(DISPATCH_TIME_NOW, 1000 * kNanosecondsPerMillisecond),
                                  DISPATCH_TIME_FOREVER, 0);
    }

exit:
    return;
}

void    DispatchLite_AfterCallBack(void* inContext) {
    SourceTuple* const         context = (SourceTuple*) inContext;
    int* const                 n = (int*)(context->context);

    require_action(dispatch_get_current_queue() == gDispatchLiteTestQueue, exit, gDispatchLiteTestErr = -1);

    *n += 1;
    gcd_ulog(kLogLevelNotice, "\t%s: n = %d\n", __ROUTINE__, *n);
    if (*n == 1) {
        gDispatchLiteTestDone = true;
    }
    else {
        gcd_ulog(kLogLevelNotice, "### Duplicate dispatch_after callback\n");
        gDispatchLiteTestErr = kDuplicateErr;
    }

exit:
    return;
}

#if( DISPATCH_LITE_CF_ENABLED )
void    DispatchLite_TestCF(void* inContext) {
    int     x;

    check(dispatch_get_current_queue() == gDispatchLiteTestQueue);

    x = (int)(intptr_t) inContext;
    gcd_ulog(kLogLevelNotice, "\t%s: x = %d\n", __ROUTINE__, x);

    gDispatchLiteTest1 += x;
    if (x == 2345) {
        CFRunLoopStop(CFRunLoopGetCurrent());
    }
}
#endif

#if( TARGET_OS_WINDOWS )
void    DispatchLite_TestWindowsMessageLoop(void* inContext) {
    int     x;

    check(dispatch_get_current_queue() == gDispatchLiteTestQueue);

    x = (int)(intptr_t) inContext;
    gcd_ulog(kLogLevelNotice, "\t%s: x = %d\n", __ROUTINE__, x);

    gDispatchLiteTest1 += x;
    if (x == 2345) {
        gDispatchLiteTestDone = true;
    }
}
#endif

void    DispatchLiteTest_WaitUntilDone(void) {
    int     timeout;

    timeout = 500;
    while (!gDispatchLiteTestDone && (timeout > 0)) {
        usleep(10000);
        --timeout;
    }
    check(gDispatchLiteTestDone);
    gDispatchLiteTestDone = false;
}

void    DispatchLiteTest_WaitUntilSourceDone(void) {
    int     timeout;

    timeout = 500;
    while (!gDispatchLiteSourceDone && (timeout > 0)) {
        usleep(10000);
        --timeout;
    }
    check(gDispatchLiteSourceDone);
    gDispatchLiteSourceDone = false;
}

#endif // !EXCLUDE_UNIT_TESTS
#endif // DISPATCH_LITE_ENABLED
